Files
renderdoc/renderdoc/driver/gl/gl_driver.cpp
T

5544 lines
205 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 Baldur Karlsson
* Copyright (c) 2014 Crytek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "gl_driver.h"
#include <algorithm>
#include "common/common.h"
#include "driver/shaders/spirv/spirv_compile.h"
#include "jpeg-compressor/jpge.h"
#include "serialise/rdcfile.h"
#include "strings/string_utils.h"
#include "gl_replay.h"
std::map<uint64_t, GLWindowingData> WrappedOpenGL::m_ActiveContexts;
void WrappedOpenGL::BuildGLExtensions()
{
m_GLExtensions.push_back("GL_ARB_arrays_of_arrays");
m_GLExtensions.push_back("GL_ARB_base_instance");
m_GLExtensions.push_back("GL_ARB_blend_func_extended");
m_GLExtensions.push_back("GL_ARB_buffer_storage");
m_GLExtensions.push_back("GL_ARB_clear_buffer_object");
m_GLExtensions.push_back("GL_ARB_clear_texture");
m_GLExtensions.push_back("GL_ARB_clip_control");
m_GLExtensions.push_back("GL_ARB_color_buffer_float");
m_GLExtensions.push_back("GL_ARB_compressed_texture_pixel_storage");
m_GLExtensions.push_back("GL_ARB_compute_shader");
m_GLExtensions.push_back("GL_ARB_compute_variable_group_size");
m_GLExtensions.push_back("GL_ARB_conditional_render_inverted");
m_GLExtensions.push_back("GL_ARB_conservative_depth");
m_GLExtensions.push_back("GL_ARB_copy_buffer");
m_GLExtensions.push_back("GL_ARB_copy_image");
m_GLExtensions.push_back("GL_ARB_cull_distance");
m_GLExtensions.push_back("GL_ARB_debug_output");
m_GLExtensions.push_back("GL_ARB_depth_buffer_float");
m_GLExtensions.push_back("GL_ARB_depth_clamp");
m_GLExtensions.push_back("GL_ARB_depth_texture");
m_GLExtensions.push_back("GL_ARB_derivative_control");
m_GLExtensions.push_back("GL_ARB_direct_state_access");
m_GLExtensions.push_back("GL_ARB_draw_buffers");
m_GLExtensions.push_back("GL_ARB_draw_buffers_blend");
m_GLExtensions.push_back("GL_ARB_draw_elements_base_vertex");
m_GLExtensions.push_back("GL_ARB_draw_indirect");
m_GLExtensions.push_back("GL_ARB_draw_instanced");
m_GLExtensions.push_back("GL_ARB_enhanced_layouts");
m_GLExtensions.push_back("GL_ARB_ES2_compatibility");
m_GLExtensions.push_back("GL_ARB_ES3_1_compatibility");
m_GLExtensions.push_back("GL_ARB_ES3_2_compatibility");
m_GLExtensions.push_back("GL_ARB_ES3_compatibility");
m_GLExtensions.push_back("GL_ARB_explicit_attrib_location");
m_GLExtensions.push_back("GL_ARB_explicit_uniform_location");
m_GLExtensions.push_back("GL_ARB_fragment_coord_conventions");
m_GLExtensions.push_back("GL_ARB_fragment_layer_viewport");
m_GLExtensions.push_back("GL_ARB_fragment_shader_interlock");
m_GLExtensions.push_back("GL_ARB_framebuffer_no_attachments");
m_GLExtensions.push_back("GL_ARB_framebuffer_object");
m_GLExtensions.push_back("GL_ARB_framebuffer_sRGB");
m_GLExtensions.push_back("GL_ARB_geometry_shader4");
m_GLExtensions.push_back("GL_ARB_get_program_binary");
m_GLExtensions.push_back("GL_ARB_get_texture_sub_image");
m_GLExtensions.push_back("GL_ARB_gl_spirv");
m_GLExtensions.push_back("GL_ARB_gpu_shader_fp64");
m_GLExtensions.push_back("GL_ARB_gpu_shader5");
m_GLExtensions.push_back("GL_ARB_half_float_pixel");
m_GLExtensions.push_back("GL_ARB_half_float_vertex");
m_GLExtensions.push_back("GL_ARB_indirect_parameters");
m_GLExtensions.push_back("GL_ARB_instanced_arrays");
m_GLExtensions.push_back("GL_ARB_internalformat_query");
m_GLExtensions.push_back("GL_ARB_internalformat_query2");
m_GLExtensions.push_back("GL_ARB_invalidate_subdata");
m_GLExtensions.push_back("GL_ARB_map_buffer_alignment");
m_GLExtensions.push_back("GL_ARB_map_buffer_range");
m_GLExtensions.push_back("GL_ARB_multi_bind");
m_GLExtensions.push_back("GL_ARB_multi_draw_indirect");
m_GLExtensions.push_back("GL_ARB_multisample");
m_GLExtensions.push_back("GL_ARB_multitexture");
m_GLExtensions.push_back("GL_ARB_occlusion_query");
m_GLExtensions.push_back("GL_ARB_occlusion_query2");
m_GLExtensions.push_back("GL_ARB_parallel_shader_compile");
m_GLExtensions.push_back("GL_ARB_pixel_buffer_object");
m_GLExtensions.push_back("GL_ARB_pipeline_statistics_query");
m_GLExtensions.push_back("GL_ARB_point_parameters");
m_GLExtensions.push_back("GL_ARB_point_sprite");
m_GLExtensions.push_back("GL_ARB_polygon_offset_clamp");
m_GLExtensions.push_back("GL_ARB_post_depth_coverage");
m_GLExtensions.push_back("GL_ARB_program_interface_query");
m_GLExtensions.push_back("GL_ARB_provoking_vertex");
m_GLExtensions.push_back("GL_ARB_query_buffer_object");
m_GLExtensions.push_back("GL_ARB_robust_buffer_access_behavior");
m_GLExtensions.push_back("GL_ARB_robustness");
m_GLExtensions.push_back("GL_ARB_robustness_application_isolation");
m_GLExtensions.push_back("GL_ARB_robustness_share_group_isolation");
m_GLExtensions.push_back("GL_ARB_sample_shading");
m_GLExtensions.push_back("GL_ARB_sampler_objects");
m_GLExtensions.push_back("GL_ARB_seamless_cube_map");
m_GLExtensions.push_back("GL_ARB_seamless_cubemap_per_texture");
m_GLExtensions.push_back("GL_ARB_separate_shader_objects");
m_GLExtensions.push_back("GL_ARB_shader_atomic_counters");
m_GLExtensions.push_back("GL_ARB_shader_atomic_counter_ops");
m_GLExtensions.push_back("GL_ARB_shader_ballot");
m_GLExtensions.push_back("GL_ARB_shader_bit_encoding");
m_GLExtensions.push_back("GL_ARB_shader_clock");
m_GLExtensions.push_back("GL_ARB_shader_draw_parameters");
m_GLExtensions.push_back("GL_ARB_shader_group_vote");
m_GLExtensions.push_back("GL_ARB_shader_image_load_store");
m_GLExtensions.push_back("GL_ARB_shader_image_size");
m_GLExtensions.push_back("GL_ARB_shader_precision");
m_GLExtensions.push_back("GL_ARB_shader_stencil_export");
m_GLExtensions.push_back("GL_ARB_shader_storage_buffer_object");
m_GLExtensions.push_back("GL_ARB_shader_subroutine");
m_GLExtensions.push_back("GL_ARB_shader_texture_image_samples");
m_GLExtensions.push_back("GL_ARB_shader_texture_lod");
m_GLExtensions.push_back("GL_ARB_shader_viewport_layer_array");
m_GLExtensions.push_back("GL_ARB_shading_language_100");
m_GLExtensions.push_back("GL_ARB_shading_language_420pack");
m_GLExtensions.push_back("GL_ARB_shading_language_include");
m_GLExtensions.push_back("GL_ARB_shading_language_packing");
m_GLExtensions.push_back("GL_ARB_shadow");
m_GLExtensions.push_back("GL_ARB_shadow_ambient");
m_GLExtensions.push_back("GL_ARB_spirv_extensions");
m_GLExtensions.push_back("GL_ARB_stencil_texturing");
m_GLExtensions.push_back("GL_ARB_sync");
m_GLExtensions.push_back("GL_ARB_tessellation_shader");
m_GLExtensions.push_back("GL_ARB_texture_barrier");
m_GLExtensions.push_back("GL_ARB_texture_border_clamp");
m_GLExtensions.push_back("GL_ARB_texture_buffer_object");
m_GLExtensions.push_back("GL_ARB_texture_buffer_object_rgb32");
m_GLExtensions.push_back("GL_ARB_texture_buffer_range");
m_GLExtensions.push_back("GL_ARB_texture_compression");
m_GLExtensions.push_back("GL_ARB_texture_compression_bptc");
m_GLExtensions.push_back("GL_ARB_texture_compression_rgtc");
m_GLExtensions.push_back("GL_ARB_texture_cube_map");
m_GLExtensions.push_back("GL_ARB_texture_cube_map_array");
m_GLExtensions.push_back("GL_ARB_texture_filter_anisotropic");
m_GLExtensions.push_back("GL_ARB_texture_float");
m_GLExtensions.push_back("GL_ARB_texture_gather");
m_GLExtensions.push_back("GL_ARB_texture_mirror_clamp_to_edge");
m_GLExtensions.push_back("GL_ARB_texture_mirrored_repeat");
m_GLExtensions.push_back("GL_ARB_texture_multisample");
m_GLExtensions.push_back("GL_ARB_texture_non_power_of_two");
m_GLExtensions.push_back("GL_ARB_texture_query_levels");
m_GLExtensions.push_back("GL_ARB_texture_query_lod");
m_GLExtensions.push_back("GL_ARB_texture_rectangle");
m_GLExtensions.push_back("GL_ARB_texture_rg");
m_GLExtensions.push_back("GL_ARB_texture_rgb10_a2ui");
m_GLExtensions.push_back("GL_ARB_texture_stencil8");
m_GLExtensions.push_back("GL_ARB_texture_storage");
m_GLExtensions.push_back("GL_ARB_texture_storage_multisample");
m_GLExtensions.push_back("GL_ARB_texture_swizzle");
m_GLExtensions.push_back("GL_ARB_texture_view");
m_GLExtensions.push_back("GL_ARB_timer_query");
m_GLExtensions.push_back("GL_ARB_transform_feedback_instanced");
m_GLExtensions.push_back("GL_ARB_transform_feedback_overflow_query");
m_GLExtensions.push_back("GL_ARB_transform_feedback2");
m_GLExtensions.push_back("GL_ARB_transform_feedback3");
m_GLExtensions.push_back("GL_ARB_uniform_buffer_object");
m_GLExtensions.push_back("GL_ARB_vertex_array_bgra");
m_GLExtensions.push_back("GL_ARB_vertex_array_object");
m_GLExtensions.push_back("GL_ARB_vertex_attrib_64bit");
m_GLExtensions.push_back("GL_ARB_vertex_attrib_binding");
m_GLExtensions.push_back("GL_ARB_vertex_buffer_object");
m_GLExtensions.push_back("GL_ARB_vertex_program");
m_GLExtensions.push_back("GL_ARB_vertex_type_10f_11f_11f_rev");
m_GLExtensions.push_back("GL_ARB_vertex_type_2_10_10_10_rev");
m_GLExtensions.push_back("GL_ARB_viewport_array");
m_GLExtensions.push_back("GL_EXT_bgra");
m_GLExtensions.push_back("GL_EXT_blend_color");
m_GLExtensions.push_back("GL_EXT_blend_equation_separate");
m_GLExtensions.push_back("GL_EXT_blend_func_separate");
m_GLExtensions.push_back("GL_EXT_blend_minmax");
m_GLExtensions.push_back("GL_EXT_blend_subtract");
m_GLExtensions.push_back("GL_EXT_debug_label");
m_GLExtensions.push_back("GL_EXT_debug_marker");
m_GLExtensions.push_back("GL_EXT_depth_bounds_test");
m_GLExtensions.push_back("GL_EXT_direct_state_access");
m_GLExtensions.push_back("GL_EXT_draw_buffers2");
m_GLExtensions.push_back("GL_EXT_draw_instanced");
m_GLExtensions.push_back("GL_EXT_draw_range_elements");
m_GLExtensions.push_back("GL_EXT_framebuffer_blit");
m_GLExtensions.push_back("GL_EXT_framebuffer_multisample");
m_GLExtensions.push_back("GL_EXT_framebuffer_multisample_blit_scaled");
m_GLExtensions.push_back("GL_EXT_framebuffer_object");
m_GLExtensions.push_back("GL_EXT_framebuffer_sRGB");
m_GLExtensions.push_back("GL_EXT_gpu_shader4");
m_GLExtensions.push_back("GL_EXT_memory_object");
m_GLExtensions.push_back("GL_EXT_memory_object_fd");
m_GLExtensions.push_back("GL_EXT_memory_object_win32");
m_GLExtensions.push_back("GL_EXT_multisample");
m_GLExtensions.push_back("GL_EXT_multi_draw_arrays");
m_GLExtensions.push_back("GL_EXT_packed_depth_stencil");
m_GLExtensions.push_back("GL_EXT_packed_float");
m_GLExtensions.push_back("GL_EXT_pixel_buffer_object");
m_GLExtensions.push_back("GL_EXT_point_parameters");
m_GLExtensions.push_back("GL_EXT_polygon_offset");
m_GLExtensions.push_back("GL_EXT_polygon_offset_clamp");
m_GLExtensions.push_back("GL_EXT_post_depth_coverage");
m_GLExtensions.push_back("GL_EXT_provoking_vertex");
m_GLExtensions.push_back("GL_EXT_raster_multisample");
m_GLExtensions.push_back("GL_EXT_semaphore");
m_GLExtensions.push_back("GL_EXT_semaphore_fd");
m_GLExtensions.push_back("GL_EXT_semaphore_win32");
m_GLExtensions.push_back("GL_EXT_shader_image_load_store");
m_GLExtensions.push_back("GL_EXT_shader_image_load_formatted");
m_GLExtensions.push_back("GL_EXT_shader_integer_mix");
m_GLExtensions.push_back("GL_EXT_shadow_funcs");
m_GLExtensions.push_back("GL_EXT_stencil_wrap");
m_GLExtensions.push_back("GL_EXT_texture_array");
m_GLExtensions.push_back("GL_EXT_texture_buffer_object");
m_GLExtensions.push_back("GL_EXT_texture_compression_dxt1");
m_GLExtensions.push_back("GL_EXT_texture_compression_rgtc");
m_GLExtensions.push_back("GL_EXT_texture_compression_s3tc");
m_GLExtensions.push_back("GL_EXT_texture_cube_map");
m_GLExtensions.push_back("GL_EXT_texture_edge_clamp");
m_GLExtensions.push_back("GL_EXT_texture_filter_anisotropic");
m_GLExtensions.push_back("GL_EXT_texture_filter_minmax");
m_GLExtensions.push_back("GL_EXT_texture_integer");
m_GLExtensions.push_back("GL_EXT_texture_lod_bias");
m_GLExtensions.push_back("GL_EXT_texture_mirror_clamp");
m_GLExtensions.push_back("GL_EXT_texture_shadow_lod");
m_GLExtensions.push_back("GL_EXT_texture_shared_exponent");
m_GLExtensions.push_back("GL_EXT_texture_snorm");
m_GLExtensions.push_back("GL_EXT_texture_sRGB");
m_GLExtensions.push_back("GL_EXT_texture_sRGB_decode");
m_GLExtensions.push_back("GL_EXT_texture_sRGB_R8");
m_GLExtensions.push_back("GL_EXT_texture_swizzle");
m_GLExtensions.push_back("GL_EXT_texture3D");
m_GLExtensions.push_back("GL_EXT_timer_query");
m_GLExtensions.push_back("GL_EXT_transform_feedback");
m_GLExtensions.push_back("GL_EXT_vertex_attrib_64bit");
m_GLExtensions.push_back("GL_EXT_win32_keyed_mutex");
m_GLExtensions.push_back("GL_GREMEDY_frame_terminator");
m_GLExtensions.push_back("GL_GREMEDY_string_marker");
m_GLExtensions.push_back("GL_KHR_blend_equation_advanced");
m_GLExtensions.push_back("GL_KHR_blend_equation_advanced_coherent");
m_GLExtensions.push_back("GL_KHR_context_flush_control");
m_GLExtensions.push_back("GL_KHR_debug");
m_GLExtensions.push_back("GL_KHR_no_error");
m_GLExtensions.push_back("GL_KHR_parallel_shader_compile");
m_GLExtensions.push_back("GL_KHR_robustness");
m_GLExtensions.push_back("GL_KHR_robust_buffer_access_behavior");
// this WGL extension is advertised in the gl ext string instead of via the wgl ext string,
// return it just in case anyone is checking for it via this place. On non-windows platforms
// it won't be reported as we do the intersection of renderdoc supported extensions and
// implementation supported extensions.
m_GLExtensions.push_back("WGL_EXT_swap_control");
/************************************************************************
Extensions I plan to support, but haven't implemented yet for one reason or another.
Usually complexity/time considerations.
Vendor specific extensions aren't listed here, or below in the 'will never support' list.
Only very important/commonly used vendor extensions will be supported, generally I'll
stick to ARB, EXT and KHR.
* GL_ARB_bindless_texture
* GL_ARB_cl_event
* GL_ARB_sparse_buffer
* GL_ARB_sparse_texture
* GL_EXT_sparse_texture2
* GL_ARB_sparse_texture2
* GL_ARB_sparse_texture_clamp <- this one is free, but no point exposing until other spares exts
* GL_EXT_x11_sync_object
* GL_KHR_texture_compression_astc_hdr <- without support for astc textures on PC hardware this
* GL_KHR_texture_compression_astc_ldr <- could be difficult. Maybe falls into the category of
'only
support if it's supported on replaying driver'
* GL_KHR_texture_compression_astc_sliced_3d
* GL_ARB_gpu_shader_int64
* GL_ARB_sample_locations
* GL_ARB_texture_filter_minmax
* GL_EXT_EGL_image_storage
* GL_EXT_external_buffer
* GL_EXT_window_rectangles
* GL_EXT_texture_sRGB_R8
* GL_EXT_shader_framebuffer_fetch
* GL_EXT_shader_framebuffer_fetch_non_coherent
* GL_EXT_multiview_timer_query
* GL_EXT_multiview_texture_multisample
* GL_EXT_multiview_tessellation_geometry_shader
************************************************************************/
/************************************************************************
Extensions I never plan to support due to only referring to old/outdated functionality listed
below.
I'm not sure what to do about GL_ARB_imaging, it seems like it's somewhat used in modern GL? For
now
I'm hoping I can get away with not reporting it but implementing the functionality it still
describes.
* GL_ARB_compatibility
* GL_ARB_fragment_program
* GL_ARB_fragment_program_shadow
* GL_ARB_fragment_shader
* GL_ARB_matrix_palette
* GL_ARB_shader_objects
* GL_ARB_texture_env_add
* GL_ARB_texture_env_combine
* GL_ARB_texture_env_crossbar
* GL_ARB_texture_env_dot3
* GL_ARB_transpose_matrix
* GL_ARB_vertex_blend
* GL_ARB_vertex_shader
* GL_ARB_window_pos
* GL_ATI_draw_buffers
* GL_ATI_texture_float
* GL_ATI_texture_mirror_once
* GL_EXT_422_pixels
* GL_EXT_abgr
* GL_EXT_bindable_uniform
* GL_EXT_blend_logic_op
* GL_EXT_clip_volume_hint
* GL_EXT_cmyka
* GL_EXT_color_subtable
* GL_EXT_compiled_vertex_array
* GL_EXT_convolution
* GL_EXT_coordinate_frame
* GL_EXT_copy_texture
* GL_EXT_cull_vertex
* GL_EXT_fog_coord
* GL_EXT_fragment_lighting
* GL_EXT_geometry_shader4
* GL_EXT_gpu_program_parameters
* GL_EXT_histogram
* GL_EXT_import_sync_object
* GL_EXT_index_array_formats
* GL_EXT_index_func
* GL_EXT_index_material
* GL_EXT_index_texture
* GL_EXT_light_texture
* GL_EXT_misc_attribute
* GL_EXT_packed_pixels
* GL_EXT_paletted_texture
* GL_EXT_pixel_transform
* GL_EXT_pixel_transform_color_table
* GL_EXT_rescale_normal
* GL_EXT_scene_marker
* GL_EXT_secondary_color
* GL_EXT_separate_shader_objects
* GL_EXT_separate_specular_color
* GL_EXT_shared_texture_palette
* GL_EXT_stencil_clear_tag
* GL_EXT_stencil_two_side
* GL_EXT_subtexture
* GL_EXT_texture_compression_latc
* GL_EXT_texture_env_add
* GL_EXT_texture_env_combine
* GL_EXT_texture_env_dot3
* GL_EXT_texture_lod
* GL_EXT_texture_object
* GL_EXT_texture_perturb_normal
* GL_EXT_texture_storage
* GL_EXT_vertex_array
* GL_EXT_vertex_array_bgra
* GL_EXT_vertex_shader
* GL_EXT_vertex_weighting
* GL_S3_s3tc
************************************************************************/
// we'll be sorting the implementation extension array, so make sure the
// sorts are identical so we can do the intersection easily
std::sort(m_GLExtensions.begin(), m_GLExtensions.end());
}
void WrappedOpenGL::BuildGLESExtensions()
{
m_GLESExtensions.push_back("GL_ARM_rgba8");
m_GLESExtensions.push_back("GL_EXT_base_instance");
m_GLESExtensions.push_back("GL_EXT_blend_func_extended");
m_GLESExtensions.push_back("GL_EXT_blend_minmax");
m_GLESExtensions.push_back("GL_EXT_buffer_storage");
m_GLESExtensions.push_back("GL_EXT_clear_texture");
m_GLESExtensions.push_back("GL_EXT_clip_control");
m_GLESExtensions.push_back("GL_EXT_clip_cull_distance");
m_GLESExtensions.push_back("GL_EXT_color_buffer_float");
m_GLESExtensions.push_back("GL_EXT_color_buffer_half_float");
m_GLESExtensions.push_back("GL_EXT_conservative_depth");
m_GLESExtensions.push_back("GL_EXT_copy_image");
m_GLESExtensions.push_back("GL_EXT_debug_label");
m_GLESExtensions.push_back("GL_EXT_debug_marker");
m_GLESExtensions.push_back("GL_EXT_depth_clamp");
m_GLESExtensions.push_back("GL_EXT_discard_framebuffer");
m_GLESExtensions.push_back("GL_EXT_disjoint_timer_query");
m_GLESExtensions.push_back("GL_EXT_draw_buffers");
m_GLESExtensions.push_back("GL_EXT_draw_buffers_indexed");
m_GLESExtensions.push_back("GL_EXT_draw_elements_base_vertex");
m_GLESExtensions.push_back("GL_EXT_draw_instanced");
m_GLESExtensions.push_back("GL_EXT_draw_transform_feedback");
m_GLESExtensions.push_back("GL_EXT_float_blend");
m_GLESExtensions.push_back("GL_EXT_frag_depth");
m_GLESExtensions.push_back("GL_EXT_geometry_point_size");
m_GLESExtensions.push_back("GL_EXT_geometry_shader");
m_GLESExtensions.push_back("GL_EXT_gpu_shader5");
m_GLESExtensions.push_back("GL_EXT_instanced_arrays");
m_GLESExtensions.push_back("GL_EXT_map_buffer_range");
m_GLESExtensions.push_back("GL_EXT_memory_object");
m_GLESExtensions.push_back("GL_EXT_memory_object_fd");
m_GLESExtensions.push_back("GL_EXT_memory_object_win32");
m_GLESExtensions.push_back("GL_EXT_multisampled_render_to_texture");
m_GLESExtensions.push_back("GL_EXT_multi_draw_arrays");
m_GLESExtensions.push_back("GL_EXT_multi_draw_indirect");
m_GLESExtensions.push_back("GL_EXT_multisample_compatibility");
m_GLESExtensions.push_back("GL_EXT_multisampled_render_to_texture2");
m_GLESExtensions.push_back("GL_EXT_occlusion_query_boolean");
m_GLESExtensions.push_back("GL_EXT_polygon_offset_clamp");
m_GLESExtensions.push_back("GL_EXT_post_depth_coverage");
m_GLESExtensions.push_back("GL_EXT_primitive_bounding_box");
m_GLESExtensions.push_back("GL_EXT_pvrtc_sRGB");
m_GLESExtensions.push_back("GL_EXT_raster_multisample");
m_GLESExtensions.push_back("GL_EXT_render_snorm");
m_GLESExtensions.push_back("GL_EXT_robustness");
m_GLESExtensions.push_back("GL_EXT_semaphore");
m_GLESExtensions.push_back("GL_EXT_semaphore_fd");
m_GLESExtensions.push_back("GL_EXT_semaphore_win32");
m_GLESExtensions.push_back("GL_EXT_separate_shader_objects");
m_GLESExtensions.push_back("GL_EXT_shader_framebuffer_fetch");
m_GLESExtensions.push_back("GL_EXT_shader_group_vote");
m_GLESExtensions.push_back("GL_EXT_shader_implicit_conversions");
m_GLESExtensions.push_back("GL_EXT_shader_integer_mix");
m_GLESExtensions.push_back("GL_EXT_shader_io_blocks");
m_GLESExtensions.push_back("GL_EXT_shader_non_constant_global_initializers");
m_GLESExtensions.push_back("GL_EXT_shader_texture_lod");
m_GLESExtensions.push_back("GL_EXT_shadow_samplers");
m_GLESExtensions.push_back("GL_EXT_sRGB");
m_GLESExtensions.push_back("GL_EXT_sRGB_write_control");
m_GLESExtensions.push_back("GL_EXT_tessellation_shader");
m_GLESExtensions.push_back("GL_EXT_texture_border_clamp");
m_GLESExtensions.push_back("GL_EXT_texture_buffer");
m_GLESExtensions.push_back("GL_EXT_texture_compression_astc_decode_mode");
m_GLESExtensions.push_back("GL_EXT_texture_compression_bptc");
m_GLESExtensions.push_back("GL_EXT_texture_compression_dxt1");
m_GLESExtensions.push_back("GL_EXT_texture_compression_rgtc");
m_GLESExtensions.push_back("GL_EXT_texture_compression_s3tc");
m_GLESExtensions.push_back("GL_EXT_texture_compression_s3tc_srgb");
m_GLESExtensions.push_back("GL_EXT_texture_cube_map_array");
m_GLESExtensions.push_back("GL_EXT_texture_filter_anisotropic");
m_GLESExtensions.push_back("GL_EXT_texture_filter_minmax");
m_GLESExtensions.push_back("GL_EXT_texture_format_BGRA8888");
m_GLESExtensions.push_back("GL_EXT_texture_lod_bias");
m_GLESExtensions.push_back("GL_EXT_texture_mirror_clamp_to_edge");
m_GLESExtensions.push_back("GL_EXT_texture_norm16");
m_GLESExtensions.push_back("GL_EXT_texture_query_lod");
m_GLESExtensions.push_back("GL_EXT_texture_rg");
m_GLESExtensions.push_back("GL_EXT_texture_shadow_lod");
m_GLESExtensions.push_back("GL_EXT_texture_sRGB_decode");
m_GLESExtensions.push_back("GL_EXT_texture_sRGB_R8");
m_GLESExtensions.push_back("GL_EXT_texture_sRGB_RG8");
m_GLESExtensions.push_back("GL_EXT_texture_storage");
m_GLESExtensions.push_back("GL_EXT_texture_type_2_10_10_10_REV");
m_GLESExtensions.push_back("GL_EXT_texture_view");
m_GLESExtensions.push_back("GL_EXT_win32_keyed_mutex");
m_GLESExtensions.push_back("GL_KHR_blend_equation_advanced");
m_GLESExtensions.push_back("GL_KHR_blend_equation_advanced_coherent");
m_GLESExtensions.push_back("GL_KHR_context_flush_control");
m_GLESExtensions.push_back("GL_KHR_debug");
m_GLESExtensions.push_back("GL_KHR_no_error");
m_GLESExtensions.push_back("GL_KHR_parallel_shader_compile");
m_GLESExtensions.push_back("GL_KHR_robustness");
m_GLESExtensions.push_back("GL_KHR_robust_buffer_access_behavior");
m_GLESExtensions.push_back("GL_KHR_texture_compression_astc_hdr");
m_GLESExtensions.push_back("GL_KHR_texture_compression_astc_ldr");
m_GLESExtensions.push_back("GL_KHR_texture_compression_astc_sliced_3d");
m_GLESExtensions.push_back("GL_NV_viewport_array");
m_GLESExtensions.push_back("GL_OES_blend_equation_separate");
m_GLESExtensions.push_back("GL_OES_blend_func_separate");
m_GLESExtensions.push_back("GL_OES_blend_subtract");
m_GLESExtensions.push_back("GL_OES_compressed_ETC1_RGB8_texture");
m_GLESExtensions.push_back("GL_OES_copy_image");
m_GLESExtensions.push_back("GL_OES_depth24");
m_GLESExtensions.push_back("GL_OES_depth32");
m_GLESExtensions.push_back("GL_OES_depth_texture");
m_GLESExtensions.push_back("GL_OES_depth_texture_cube_map");
m_GLESExtensions.push_back("GL_OES_draw_buffers_indexed");
m_GLESExtensions.push_back("GL_OES_draw_elements_base_vertex");
m_GLESExtensions.push_back("GL_OES_element_index_uint");
m_GLESExtensions.push_back("GL_OES_fbo_render_mipmap");
m_GLESExtensions.push_back("GL_OES_framebuffer_object");
m_GLESExtensions.push_back("GL_OES_geometry_shader");
m_GLESExtensions.push_back("GL_OES_gpu_shader5");
m_GLESExtensions.push_back("GL_OES_mapbuffer");
m_GLESExtensions.push_back("GL_OES_packed_depth_stencil");
m_GLESExtensions.push_back("GL_OES_primitive_bounding_box");
m_GLESExtensions.push_back("GL_OES_rgb8_rgba8");
m_GLESExtensions.push_back("GL_OES_sample_shading");
m_GLESExtensions.push_back("GL_OES_standard_derivatives");
m_GLESExtensions.push_back("GL_OES_tessellation_shader");
m_GLESExtensions.push_back("GL_OES_texture_3D");
m_GLESExtensions.push_back("GL_OES_texture_border_clamp");
m_GLESExtensions.push_back("GL_OES_texture_buffer");
m_GLESExtensions.push_back("GL_OES_texture_compression_astc");
m_GLESExtensions.push_back("GL_OES_texture_cube_map");
m_GLESExtensions.push_back("GL_OES_texture_cube_map_array");
m_GLESExtensions.push_back("GL_OES_texture_float");
m_GLESExtensions.push_back("GL_OES_texture_float_linear");
m_GLESExtensions.push_back("GL_OES_texture_half_float");
m_GLESExtensions.push_back("GL_OES_texture_half_float_linear");
m_GLESExtensions.push_back("GL_OES_texture_mirrored_repeat");
m_GLESExtensions.push_back("GL_OES_texture_npot");
m_GLESExtensions.push_back("GL_OES_texture_stencil8");
m_GLESExtensions.push_back("GL_OES_texture_storage_multisample_2d_array");
m_GLESExtensions.push_back("GL_OES_texture_view");
m_GLESExtensions.push_back("GL_OES_vertex_array_object");
m_GLESExtensions.push_back("GL_OES_vertex_half_float");
m_GLESExtensions.push_back("GL_OES_viewport_array");
m_GLESExtensions.push_back("GL_OVR_multiview");
m_GLESExtensions.push_back("GL_OVR_multiview2");
m_GLESExtensions.push_back("GL_OVR_multiview_multisampled_render_to_texture");
m_GLESExtensions.push_back("GL_QCOM_texture_foveated");
// advertise EGL extensions in the gl ext string, just in case anyone is checking it for
// this way.
m_GLESExtensions.push_back("EGL_KHR_create_context");
m_GLESExtensions.push_back("EGL_KHR_surfaceless_context");
// we'll be sorting the implementation extension array, so make sure the
// sorts are identical so we can do the intersection easily
std::sort(m_GLESExtensions.begin(), m_GLESExtensions.end());
/***********************************************************************
Unsorted GLES extensions that are not yet supported. Nothing here says whether it's
possible to support, will never be supported, or unlikely, etc.
As above - only OES, KHR, and EXT extensions listed
* GL_EXT_compressed_ETC1_RGB8_sub_texture
* GL_EXT_EGL_image_array
* GL_EXT_EGL_image_external_wrap_modes
* GL_EXT_EGL_image_storage
* GL_EXT_external_buffer
* GL_EXT_multiview_draw_buffers
* GL_EXT_multiview_tessellation_geometry_shader
* GL_EXT_multiview_texture_multisample
* GL_EXT_multiview_timer_query
* GL_EXT_protected_textures
* GL_EXT_read_format_bgra
* GL_EXT_shader_framebuffer_fetch_non_coherent
* GL_EXT_shader_pixel_local_storage
* GL_EXT_shader_pixel_local_storage2
* GL_EXT_sparse_texture
* GL_EXT_sparse_texture2
* GL_EXT_tessellation_point_size
* GL_EXT_texture_compression_astc_decode_mode_rgb9e5
* GL_EXT_texture_format_sRGB_override
* GL_EXT_unpack_subimage
* GL_EXT_window_rectangles
* GL_EXT_YUV_target
* GL_OES_byte_coordinates
* GL_OES_compressed_paletted_texture
* GL_OES_draw_texture
* GL_OES_EGL_image
* GL_OES_EGL_image_external
* GL_OES_EGL_image_external_essl3
* GL_OES_EGL_sync
* GL_OES_extended_matrix_palette
* GL_OES_fixed_point
* GL_OES_fragment_precision_high
* GL_OES_get_program_binary
* GL_OES_matrix_get
* GL_OES_matrix_palette
* GL_OES_point_size_array
* GL_OES_point_sprite
* GL_OES_query_matrix
* GL_OES_read_format
* GL_OES_required_internalformat
* GL_OES_sample_variables
* GL_OES_shader_image_atomic
* GL_OES_shader_io_blocks
* GL_OES_shader_multisample_interpolation
* GL_OES_single_precision
* GL_OES_stencil_wrap
* GL_OES_stencil1
* GL_OES_stencil4
* GL_OES_stencil8
* GL_OES_surfaceless_context
* GL_OES_texture_env_crossbar
* GL_OES_vertex_type_10_10_10_2
************************************************************************/
}
WrappedOpenGL::WrappedOpenGL(GLPlatform &platform)
: m_Platform(platform), m_ScratchSerialiser(new StreamWriter(1024), Ownership::Stream)
{
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedOpenGL));
BuildGLExtensions();
BuildGLESExtensions();
// by default we assume OpenGL driver
SetDriverType(RDCDriver::OpenGL);
m_Replay = new GLReplay(this);
m_StructuredFile = &m_StoredStructuredData;
uint32_t flags = WriteSerialiser::ChunkDuration | WriteSerialiser::ChunkTimestamp |
WriteSerialiser::ChunkThreadID;
if(RenderDoc::Inst().GetCaptureOptions().captureCallstacks)
flags |= WriteSerialiser::ChunkCallstack;
m_ScratchSerialiser.SetChunkMetadataRecording(flags);
m_ScratchSerialiser.SetVersion(GLInitParams::CurrentVersion);
m_SectionVersion = GLInitParams::CurrentVersion;
m_NoCtxFrames = 0;
m_FailedFrame = 0;
m_FailedReason = CaptureSucceeded;
m_Failures = 0;
m_SuccessfulCapture = true;
m_FailureReason = CaptureSucceeded;
m_UsesVRMarkers = false;
m_SuppressDebugMessages = false;
m_DrawcallStack.push_back(&m_ParentDrawcall);
m_CurEventID = 0;
m_CurDrawcallID = 0;
m_FirstEventID = 0;
m_LastEventID = ~0U;
m_FetchCounters = false;
RDCEraseEl(m_ActiveQueries);
m_ActiveConditional = false;
m_ActiveFeedback = false;
if(RenderDoc::Inst().IsReplayApp())
{
m_State = CaptureState::LoadingReplaying;
}
else
{
m_State = CaptureState::BackgroundCapturing;
}
m_DeviceRecord = NULL;
m_ResourceManager = new GLResourceManager(m_State, this);
m_ScratchSerialiser.SetUserData(GetResourceManager());
m_DeviceResourceID =
GetResourceManager()->RegisterResource(GLResource(NULL, eResSpecial, eSpecialResDevice));
m_ContextResourceID =
GetResourceManager()->RegisterResource(GLResource(NULL, eResSpecial, eSpecialResContext));
if(!RenderDoc::Inst().IsReplayApp())
{
m_DeviceRecord = GetResourceManager()->AddResourceRecord(m_DeviceResourceID);
m_DeviceRecord->DataInSerialiser = false;
m_DeviceRecord->Length = 0;
m_DeviceRecord->InternalResource = true;
m_ContextRecord = GetResourceManager()->AddResourceRecord(m_ContextResourceID);
m_ContextRecord->DataInSerialiser = false;
m_ContextRecord->Length = 0;
m_ContextRecord->InternalResource = true;
}
else
{
m_DeviceRecord = m_ContextRecord = NULL;
ResourceIDGen::SetReplayResourceIDs();
}
rdcspv::Init();
RenderDoc::Inst().RegisterShutdownFunction(&rdcspv::Shutdown);
m_CurrentDefaultFBO = 0;
m_CurChunkOffset = 0;
m_AddedDrawcall = false;
m_CurCtxDataTLS = Threading::AllocateTLSSlot();
}
void WrappedOpenGL::Initialise(GLInitParams &params, uint64_t sectionVersion,
const ReplayOptions &opts)
{
m_SectionVersion = sectionVersion;
m_GlobalInitParams = params;
m_ReplayOptions = opts;
m_ArrayMS.Create();
}
void WrappedOpenGL::MarkReferencedWhileCapturing(GLResourceRecord *record, FrameRefType refType)
{
if(!record || !IsCaptureMode(m_State))
return;
GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), refType);
}
void WrappedOpenGL::CreateReplayBackbuffer(const GLInitParams &params, ResourceId fboOrigId,
GLuint &fbo, rdcstr bbname)
{
GLuint col = 0, depth = 0;
WrappedOpenGL &drv = *this;
GLuint unpackbuf = 0;
GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&unpackbuf);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0);
drv.glGenFramebuffers(1, &fbo);
drv.glBindFramebuffer(eGL_FRAMEBUFFER, fbo);
m_CurrentDefaultFBO = fbo;
GLenum colfmt = eGL_RGBA8;
if(params.colorBits == 32)
{
colfmt = params.isSRGB ? eGL_SRGB8_ALPHA8 : eGL_RGBA8;
}
else if(params.colorBits == 24)
{
colfmt = params.isSRGB ? eGL_SRGB8 : eGL_RGB8;
}
else if(params.colorBits == 16)
{
RDCASSERT(!params.isSRGB);
// 5:6:5 is almost certainly not used in desktop GL as a backbuffer format, and is only required
// to be supported from 4.2 onwards, so only replicate it on a GLES capture.
if(IsGLES)
colfmt = eGL_RGB565;
else
colfmt = eGL_RGB8;
}
else
{
RDCERR("Unexpected # colour bits: %d", params.colorBits);
}
GLenum target = eGL_TEXTURE_2D;
if(params.multiSamples > 1)
target = eGL_TEXTURE_2D_MULTISAMPLE;
drv.glGenTextures(1, &col);
drv.glBindTexture(target, col);
m_Textures[GetResourceManager()->GetID(TextureRes(GetCtx(), col))].creationFlags |=
TextureCategory::SwapBuffer;
uint32_t width = RDCMAX(1U, params.width);
uint32_t height = RDCMAX(1U, params.height);
if(params.multiSamples > 1)
{
drv.glTextureStorage2DMultisampleEXT(col, target, params.multiSamples, colfmt, width, height,
true);
}
else
{
drv.glTextureImage2DEXT(col, target, 0, colfmt, width, height, 0, GetBaseFormat(colfmt),
GetDataType(colfmt), NULL);
drv.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0);
drv.glTexParameteri(target, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
drv.glTexParameteri(target, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
drv.glTexParameteri(target, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
drv.glTexParameteri(target, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
}
drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, target, col, 0);
drv.glViewport(0, 0, width, height);
if(params.depthBits > 0 || params.stencilBits > 0)
{
drv.glGenTextures(1, &depth);
drv.glBindTexture(target, depth);
GLenum depthfmt = eGL_DEPTH32F_STENCIL8;
bool stencil = false;
if(params.stencilBits == 8)
{
stencil = true;
if(params.depthBits == 32)
depthfmt = eGL_DEPTH32F_STENCIL8;
else if(params.depthBits == 24)
depthfmt = eGL_DEPTH24_STENCIL8;
else if(params.depthBits == 0)
depthfmt = eGL_STENCIL_INDEX8;
else
RDCERR("Unexpected combination of depth & stencil bits: %d & %d", params.depthBits,
params.stencilBits);
}
else if(params.stencilBits == 0)
{
if(params.depthBits == 32)
depthfmt = eGL_DEPTH_COMPONENT32F;
else if(params.depthBits == 24)
depthfmt = eGL_DEPTH_COMPONENT24;
else if(params.depthBits == 16)
depthfmt = eGL_DEPTH_COMPONENT16;
else
RDCERR("Unexpected # depth bits: %d", params.depthBits);
}
else
RDCERR("Unexpected # stencil bits: %d", params.stencilBits);
m_Textures[GetResourceManager()->GetID(TextureRes(GetCtx(), depth))].creationFlags |=
TextureCategory::SwapBuffer;
if(params.multiSamples > 1)
{
drv.glTextureStorage2DMultisampleEXT(depth, target, params.multiSamples, depthfmt, width,
height, true);
}
else
{
drv.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0);
drv.glTextureImage2DEXT(depth, target, 0, depthfmt, width, height, 0, GetBaseFormat(depthfmt),
GetDataType(depthfmt), NULL);
}
if(stencil && params.depthBits == 0)
drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, target, depth, 0);
else if(stencil)
drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, target, depth, 0);
else
drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, target, depth, 0);
}
// give the backbuffer a default clear color
float clearcol[] = {0.0f, 0.0f, 0.0f, 1.0f};
drv.glClearBufferfv(eGL_COLOR, 0, clearcol);
if(params.depthBits > 0 || params.stencilBits > 0)
drv.glClearBufferfi(eGL_DEPTH_STENCIL, 0, 1.0f, 0);
GetResourceManager()->AddLiveResource(fboOrigId, FramebufferRes(GetCtx(), fbo));
AddResource(fboOrigId, ResourceType::SwapchainImage, "");
GetReplay()->GetResourceDesc(fboOrigId).SetCustomName(bbname + " FBO");
ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), col));
rdcstr name = bbname + " Color";
GetResourceManager()->SetName(colorId, name);
// we'll add the chunk later when we re-process it.
AddResource(colorId, ResourceType::SwapchainImage, name.c_str());
GetReplay()->GetResourceDesc(colorId).SetCustomName(name);
GetReplay()->GetResourceDesc(fboOrigId).derivedResources.push_back(colorId);
GetReplay()->GetResourceDesc(colorId).parentResources.push_back(fboOrigId);
if(depth)
{
ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), depth));
name = bbname + (params.stencilBits > 0 ? " Depth-stencil" : " Depth");
GetResourceManager()->SetName(depthId, name);
// we'll add the chunk later when we re-process it.
AddResource(depthId, ResourceType::SwapchainImage, name.c_str());
GetReplay()->GetResourceDesc(depthId).SetCustomName(name);
GetReplay()->GetResourceDesc(fboOrigId).derivedResources.push_back(depthId);
GetReplay()->GetResourceDesc(depthId).parentResources.push_back(fboOrigId);
}
if(fbo == m_Global_FBO0)
{
GetReplay()->GetResourceDesc(fboOrigId).initialisationChunks.clear();
GetReplay()->GetResourceDesc(fboOrigId).initialisationChunks.push_back(m_InitChunkIndex);
GetReplay()->GetResourceDesc(colorId).initialisationChunks.clear();
GetReplay()->GetResourceDesc(colorId).initialisationChunks.push_back(m_InitChunkIndex);
if(depth)
{
ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), depth));
GetReplay()->GetResourceDesc(depthId).initialisationChunks.clear();
GetReplay()->GetResourceDesc(depthId).initialisationChunks.push_back(m_InitChunkIndex);
}
}
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, unpackbuf);
}
rdcstr WrappedOpenGL::GetChunkName(uint32_t idx)
{
if((SystemChunk)idx < SystemChunk::FirstDriverChunk)
return ToStr((SystemChunk)idx);
return ToStr((GLChunk)idx);
}
WrappedOpenGL::~WrappedOpenGL()
{
if(m_IndirectBuffer)
GL.glDeleteBuffers(1, &m_IndirectBuffer);
m_ArrayMS.Destroy();
SAFE_DELETE(m_FrameReader);
GetResourceManager()->ClearReferencedResources();
GetResourceManager()->ReleaseCurrentResource(m_DeviceResourceID);
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
if(it->second.m_ContextDataRecord)
{
RDCASSERT(it->second.m_ContextDataRecord->GetRefCount() == 1);
it->second.m_ContextDataRecord->Delete(GetResourceManager());
GetResourceManager()->ReleaseCurrentResource(it->second.m_ContextDataResourceID);
}
}
if(m_ContextRecord)
{
RDCASSERT(m_ContextRecord->GetRefCount() == 1);
m_ContextRecord->Delete(GetResourceManager());
}
GetResourceManager()->ReleaseCurrentResource(m_ContextResourceID);
if(m_DeviceRecord)
{
RDCASSERT(m_DeviceRecord->GetRefCount() == 1);
m_DeviceRecord->Delete(GetResourceManager());
}
m_ResourceManager->Shutdown();
SAFE_DELETE(m_ResourceManager);
for(size_t i = 0; i < m_CtxDataVector.size(); i++)
delete m_CtxDataVector[i];
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
delete m_Replay;
}
ContextPair &WrappedOpenGL::GetCtx()
{
GLContextTLSData *ret = (GLContextTLSData *)Threading::GetTLSValue(m_CurCtxDataTLS);
if(ret)
return ret->ctxPair;
return m_EmptyTLSData.ctxPair;
}
GLResourceRecord *WrappedOpenGL::GetContextRecord()
{
GLContextTLSData *ret = (GLContextTLSData *)Threading::GetTLSValue(m_CurCtxDataTLS);
if(ret && ret->ctxRecord)
{
return ret->ctxRecord;
}
else
{
ContextData &dat = GetCtxData();
dat.CreateResourceRecord(this, GetCtx().ctx);
return dat.m_ContextDataRecord;
}
}
WrappedOpenGL::ContextData &WrappedOpenGL::GetCtxData()
{
return m_ContextData[GetCtx().ctx];
}
////////////////////////////////////////////////////////////////
// Windowing/setup/etc
////////////////////////////////////////////////////////////////
void WrappedOpenGL::DeleteContext(void *contextHandle)
{
ContextData &ctxdata = m_ContextData[contextHandle];
RenderDoc::Inst().RemoveDeviceFrameCapturer(ctxdata.ctx);
// delete the context
GetResourceManager()->DeleteContext(contextHandle);
bool lastInGroup = true;
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
// if we find another context that's not this one, but is in the same share group, we're note
// the last
if(it->second.shareGroup == ctxdata.shareGroup && it->second.ctx &&
it->second.ctx != contextHandle)
{
lastInGroup = false;
break;
}
}
// if this is the last context in the share group, delete the group.
if(lastInGroup)
{
delete ctxdata.shareGroup;
}
if(ctxdata.built && ctxdata.ready)
{
ctxdata.ArrayMS.Destroy();
if(ctxdata.Program)
GL.glDeleteProgram(ctxdata.Program);
if(ctxdata.ArrayBuffer)
GL.glDeleteBuffers(1, &ctxdata.ArrayBuffer);
if(ctxdata.GlyphTexture)
GL.glDeleteTextures(1, &ctxdata.GlyphTexture);
}
if(ctxdata.m_ClientMemoryVBOs[0])
glDeleteBuffers(ARRAY_COUNT(ctxdata.m_ClientMemoryVBOs), ctxdata.m_ClientMemoryVBOs);
if(ctxdata.m_ClientMemoryIBO)
glDeleteBuffers(1, &ctxdata.m_ClientMemoryIBO);
if(ctxdata.m_ContextDataRecord)
{
RDCASSERT(ctxdata.m_ContextDataRecord->GetRefCount() == 1);
ctxdata.m_ContextDataRecord->Delete(GetResourceManager());
GetResourceManager()->ReleaseCurrentResource(ctxdata.m_ContextDataResourceID);
ctxdata.m_ContextDataRecord = NULL;
}
m_LastContexts.removeOneIf(
[contextHandle](const GLWindowingData &ctx) { return ctx.ctx == contextHandle; });
for(auto it = ctxdata.windows.begin(); it != ctxdata.windows.end();)
{
void *wndHandle = it->first;
it++;
ctxdata.UnassociateWindow(this, wndHandle);
}
m_ContextData.erase(contextHandle);
}
void WrappedOpenGL::ContextData::UnassociateWindow(WrappedOpenGL *driver, void *wndHandle)
{
auto it = windows.find(wndHandle);
if(it != windows.end())
{
if(it->second.first != WindowingSystem::Headless && IsCaptureMode(driver->GetState()))
Keyboard::RemoveInputWindow(it->second.first, wndHandle);
windows.erase(wndHandle);
RenderDoc::Inst().RemoveFrameCapturer(ctx, wndHandle);
}
}
void WrappedOpenGL::ContextData::AssociateWindow(WrappedOpenGL *driver, WindowingSystem winSystem,
void *wndHandle)
{
auto it = windows.find(wndHandle);
if(it == windows.end())
{
RenderDoc::Inst().AddFrameCapturer(ctx, wndHandle, driver);
if(winSystem != WindowingSystem::Headless && IsCaptureMode(driver->GetState()))
Keyboard::AddInputWindow(winSystem, wndHandle);
}
windows[wndHandle] = {winSystem, Timing::GetUnixTimestamp()};
}
void WrappedOpenGL::ContextData::CreateResourceRecord(WrappedOpenGL *driver, void *suppliedCtx)
{
if(m_ContextDataResourceID == ResourceId() ||
!driver->GetResourceManager()->HasResourceRecord(m_ContextDataResourceID))
{
m_ContextDataResourceID = driver->GetResourceManager()->RegisterResource(
GLResource(suppliedCtx, eResSpecial, eSpecialResContext));
m_ContextDataRecord = driver->GetResourceManager()->AddResourceRecord(m_ContextDataResourceID);
m_ContextDataRecord->DataInSerialiser = false;
m_ContextDataRecord->Length = 0;
m_ContextDataRecord->InternalResource = true;
}
}
void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext,
GLInitParams initParams, bool core, bool attribsCreate)
{
RDCLOG("%s context %p created %s, sharing with context %p", core ? "Core" : "Compatibility",
winData.ctx, attribsCreate ? "with attribs" : "without attribs", shareContext);
ContextData &ctxdata = m_ContextData[winData.ctx];
ctxdata.ctx = winData.ctx;
ctxdata.isCore = core;
ctxdata.attribsCreate = attribsCreate;
ctxdata.initParams = initParams;
if(shareContext == NULL)
{
// no sharing, allocate a new group
ctxdata.shareGroup = new ContextShareGroup(m_Platform, winData);
}
else
{
// use the same shareGroup ID as the share context.
ctxdata.shareGroup = GetShareGroup(shareContext);
}
RenderDoc::Inst().AddDeviceFrameCapturer(ctxdata.ctx, this);
// re-configure callstack capture, since WrappedOpenGL constructor may run too early
uint32_t flags = m_ScratchSerialiser.GetChunkMetadataRecording();
if(RenderDoc::Inst().GetCaptureOptions().captureCallstacks)
flags |= WriteSerialiser::ChunkCallstack;
else
flags &= ~WriteSerialiser::ChunkCallstack;
m_ScratchSerialiser.SetChunkMetadataRecording(flags);
}
bool WrappedOpenGL::ForceSharedObjects(void *oldContext, void *newContext)
{
ContextData &olddata = m_ContextData[oldContext];
ContextData &newdata = m_ContextData[newContext];
RDCLOG("Forcibly sharing %p with %p", newContext, oldContext);
if(newdata.built)
{
RDCERR("wglShareLists called after wglMakeCurrent - this is not supported and will break.");
return false;
}
newdata.shareGroup = olddata.shareGroup;
return true;
}
void WrappedOpenGL::RegisterReplayContext(GLWindowingData winData, void *shareContext, bool core,
bool attribsCreate)
{
ContextData &ctxdata = m_ContextData[winData.ctx];
ctxdata.ctx = winData.ctx;
ctxdata.isCore = core;
ctxdata.attribsCreate = attribsCreate;
if(shareContext == NULL)
{
// create the sharegroup
ctxdata.shareGroup = new ContextShareGroup(m_Platform, winData);
}
else
{
// use the same shareGroup ID as the share context.
ctxdata.shareGroup = GetShareGroup(shareContext);
}
ActivateContext(winData);
}
void WrappedOpenGL::UnregisterReplayContext(GLWindowingData windata)
{
void *contextHandle = windata.ctx;
ContextData &ctxdata = m_ContextData[contextHandle];
m_Platform.DeleteReplayContext(windata);
bool lastInGroup = true;
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
// if we find another context that's not this one, but is in the same share group, we're note
// the last
if(it->second.shareGroup == ctxdata.shareGroup && it->second.ctx &&
it->second.ctx != contextHandle)
{
lastInGroup = false;
break;
}
}
// if this is the last context in the share group, delete the group.
if(lastInGroup)
{
delete ctxdata.shareGroup;
}
m_ContextData.erase(contextHandle);
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_ContextConfiguration(SerialiserType &ser, void *ctx)
{
SERIALISE_ELEMENT_LOCAL(Context, m_ContextData[ctx].m_ContextDataResourceID);
SERIALISE_ELEMENT_LOCAL(FBO, m_ContextData[ctx].m_ContextFBOID);
SERIALISE_ELEMENT_LOCAL(InitParams, m_ContextData[ctx].initParams);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading() && FBO != ResourceId())
{
// we might encounter multiple instances of this chunk per frame, so only do work on the first
// one
if(!GetResourceManager()->HasLiveResource(FBO))
{
rdcstr name;
// also add a simple resource descriptor for the context
AddResource(Context, ResourceType::Device, "Context");
if(m_CurrentDefaultFBO == 0)
{
// if we haven't created a default FBO yet this is the first. Give it a nice friendly name
name = "Backbuffer";
}
else
{
// if not, we have multiple FBOs and we want to distinguish them. Give the subsequent
// backbuffers unique names
name = GetReplay()->GetResourceDesc(Context).name + " Backbuffer";
}
GLuint fbo = 0;
CreateReplayBackbuffer(InitParams, FBO, fbo, name);
}
m_CurrentDefaultFBO = GetResourceManager()->GetLiveResource(FBO).name;
}
return true;
}
void WrappedOpenGL::ActivateContext(GLWindowingData winData)
{
m_ActiveContexts[Threading::GetCurrentID()] = winData;
if(!winData.ctx)
return;
void *contextHandle = winData.ctx;
m_LastContexts.removeOneIf(
[contextHandle](const GLWindowingData &ctx) { return ctx.ctx == contextHandle; });
m_LastContexts.push_back(winData);
if(m_LastContexts.size() > 10)
m_LastContexts.erase(0);
if(IsActiveCapturing(m_State))
{
// fetch any initial states needed. Note this is insufficient, and doesn't handle the case
// where we might just suddenly start getting commands on a thread that already has a context
// active. For now we assume we'll only get GL commands from a single thread
//
// First we process any queued fetches from the context itself (i.e. non-shared resources),
// then from the context's share group.
for(void *ctx : {(void *)winData.ctx, (void *)GetShareGroup(winData.ctx)})
{
QueuedResource fetch;
fetch.res.ContextShareGroup = ctx;
size_t before = m_QueuedInitialFetches.size();
auto it = std::lower_bound(m_QueuedInitialFetches.begin(), m_QueuedInitialFetches.end(), fetch);
size_t i = it - m_QueuedInitialFetches.begin();
while(i < m_QueuedInitialFetches.size() && it->res.ContextShareGroup == ctx)
{
GetResourceManager()->ContextPrepare_InitialState(it->res);
m_QueuedInitialFetches.erase(i);
}
size_t after = m_QueuedInitialFetches.size();
(void)before;
(void)after;
RDCDEBUG("Prepared %zu resources on context/sharegroup %p, %zu left", before - after, ctx,
after);
}
}
// also if there are any queued releases, process them now
if(!m_QueuedReleases.empty())
{
for(void *ctx : {(void *)winData.ctx, (void *)GetShareGroup(winData.ctx)})
{
QueuedResource fetch;
fetch.res.ContextShareGroup = ctx;
size_t before = m_QueuedReleases.size();
auto it = std::lower_bound(m_QueuedReleases.begin(), m_QueuedReleases.end(), fetch);
size_t i = it - m_QueuedReleases.begin();
while(it != m_QueuedReleases.end() && it->res.ContextShareGroup == ctx)
{
ReleaseResource(it->res);
m_QueuedReleases.erase(i);
}
size_t after = m_QueuedReleases.size();
(void)before;
(void)after;
RDCDEBUG("Released %zu resources on context/sharegroup %p, %zu left", before - after, ctx,
after);
}
}
ContextData &ctxdata = m_ContextData[winData.ctx];
ctxdata.CreateResourceRecord(this, winData.ctx);
// update thread-local context pair
{
GLContextTLSData *tlsData = (GLContextTLSData *)Threading::GetTLSValue(m_CurCtxDataTLS);
if(tlsData)
{
tlsData->ctxPair = {winData.ctx, GetShareGroup(winData.ctx)};
tlsData->ctxRecord = ctxdata.m_ContextDataRecord;
}
else
{
tlsData = new GLContextTLSData(ContextPair({winData.ctx, GetShareGroup(winData.ctx)}),
ctxdata.m_ContextDataRecord);
m_CtxDataVector.push_back(tlsData);
Threading::SetTLSValue(m_CurCtxDataTLS, tlsData);
}
}
if(!ctxdata.built)
{
ctxdata.built = true;
if(IsCaptureMode(m_State))
RDCLOG("Activating new GL context: %s / %s / %s", GL.glGetString(eGL_VENDOR),
GL.glGetString(eGL_RENDERER), GL.glGetString(eGL_VERSION));
const rdcarray<rdcstr> &globalExts = IsGLES ? m_GLESExtensions : m_GLExtensions;
if(HasExt[KHR_debug] && GL.glDebugMessageCallback &&
RenderDoc::Inst().GetCaptureOptions().apiValidation)
{
GL.glDebugMessageCallback(&DebugSnoopStatic, this);
GL.glEnable(eGL_DEBUG_OUTPUT_SYNCHRONOUS);
}
rdcarray<rdcstr> implExts;
int ctxVersion = 0;
bool ctxGLES = false;
GetContextVersion(ctxGLES, ctxVersion);
// only use glGetStringi on 3.0 contexts and above (ES and GL), even if we have the function
// pointer
if(GL.glGetIntegerv && GL.glGetStringi && ctxVersion >= 30)
{
GLuint numExts = 0;
GL.glGetIntegerv(eGL_NUM_EXTENSIONS, (GLint *)&numExts);
for(GLuint i = 0; i < numExts; i++)
implExts.push_back((const char *)GL.glGetStringi(eGL_EXTENSIONS, i));
}
else if(GL.glGetString)
{
rdcstr implExtString = (const char *)GL.glGetString(eGL_EXTENSIONS);
split(implExtString, implExts, ' ');
}
else
{
RDCERR("No functions to fetch implementation's extensions!");
}
std::sort(implExts.begin(), implExts.end());
// intersection of implExts and globalExts into ctx.glExts
{
for(size_t i = 0, j = 0; i < implExts.size() && j < globalExts.size();)
{
const rdcstr &a = implExts[i];
const rdcstr &b = globalExts[j];
if(a == b)
{
ctxdata.glExts.push_back(a);
i++;
j++;
}
else if(a < b)
{
i++;
}
else if(b < a)
{
j++;
}
}
}
// this extension is something RenderDoc will support even if the impl
// doesn't. https://renderdoc.org/debug_tool.txt
ctxdata.glExts.push_back("GL_EXT_debug_tool");
// similarly we report all the debug extensions so that applications can use them freely - we
// don't call into the driver so we don't need to care if the driver supports them
ctxdata.glExts.push_back("GL_KHR_debug");
ctxdata.glExts.push_back("GL_EXT_debug_label");
ctxdata.glExts.push_back("GL_EXT_debug_marker");
if(!IsGLES)
{
ctxdata.glExts.push_back("GL_GREMEDY_frame_terminator");
ctxdata.glExts.push_back("GL_GREMEDY_string_marker");
}
merge(ctxdata.glExts, ctxdata.glExtsString, ' ');
if(GL.glGetIntegerv)
{
GLint mj = 0, mn = 0;
GL.glGetIntegerv(eGL_MAJOR_VERSION, &mj);
GL.glGetIntegerv(eGL_MINOR_VERSION, &mn);
int ver = mj * 10 + mn;
ctxdata.version = ver;
if(ver > GLCoreVersion || (!GLIsCore && ctxdata.isCore))
{
GLCoreVersion = ver;
GLIsCore = ctxdata.isCore;
DoVendorChecks(m_Platform, winData);
}
}
if(IsCaptureMode(m_State))
{
// check if we already have VAO 0 registered for this context. This could be possible if
// VAOs are shared and a previous context in the share group created it.
GLResource vao0 = VertexArrayRes(GetCtx(), 0);
if(!GetResourceManager()->HasCurrentResource(vao0))
{
ResourceId id = GetResourceManager()->RegisterResource(vao0);
GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
RDCASSERT(record);
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::glGenVertexArrays);
GLuint zero = 0;
Serialise_glGenVertexArrays(ser, 1, &zero);
record->AddChunk(scope.Get());
}
// give it a name
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::glObjectLabel);
Serialise_glObjectLabel(ser, eGL_VERTEX_ARRAY, 0, -1, "Default VAO");
record->AddChunk(scope.Get());
}
// we immediately mark it dirty since the vertex array tracking functions expect a proper
// VAO
GetResourceManager()->MarkDirtyResource(id);
}
// we also do the same for FBO 0, but we must force it not to be shared as even if FBOs are
// shared the FBO0 may not be :(.
GLResource fbo0 = FramebufferRes({GetCtx().ctx, GetCtx().ctx}, 0);
if(!GetResourceManager()->HasCurrentResource(fbo0))
ctxdata.m_ContextFBOID = GetResourceManager()->RegisterResource(fbo0);
}
}
// if we're capturing, we need to serialise out the changed state vector
if(IsActiveCapturing(m_State))
{
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::MakeContextCurrent);
Serialise_BeginCaptureFrame(ser);
GetContextRecord()->AddChunk(scope.Get());
}
// also serialise out this context's backbuffer params
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::ContextConfiguration);
Serialise_ContextConfiguration(ser, winData.ctx);
GetContextRecord()->AddChunk(scope.Get());
}
}
// we create these buffers last after serialising the apply of the new state, so that in the
// event that this context is created mid-capture, we don't serialise out buffer binding calls
// that trash the state of the previous context while creating these buffers.
if(ctxdata.m_ClientMemoryIBO == 0 && IsCaptureMode(m_State))
{
PUSH_CURRENT_CHUNK;
GLuint prevArrayBuffer = 0;
glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint *)&prevArrayBuffer);
GLuint prevElementArrayBuffer = 0;
glGetIntegerv(eGL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint *)&prevElementArrayBuffer);
// Initialize VBOs used in case we copy from client memory.
gl_CurChunk = GLChunk::glGenBuffers;
glGenBuffers(ARRAY_COUNT(ctxdata.m_ClientMemoryVBOs), ctxdata.m_ClientMemoryVBOs);
for(size_t i = 0; i < ARRAY_COUNT(ctxdata.m_ClientMemoryVBOs); i++)
{
gl_CurChunk = GLChunk::glBindBuffer;
glBindBuffer(eGL_ARRAY_BUFFER, ctxdata.m_ClientMemoryVBOs[i]);
gl_CurChunk = GLChunk::glBufferData;
glBufferData(eGL_ARRAY_BUFFER, 64, NULL, eGL_DYNAMIC_DRAW);
// we mark these buffers as internal since initial contents are not needed - they're
// entirely handled internally and buffer data is uploaded immediately before draws - and
// we don't want them to be pulled in unless explicitly referenced.
GetResourceManager()->SetInternalResource(BufferRes(GetCtx(), ctxdata.m_ClientMemoryVBOs[i]));
if(HasExt[KHR_debug])
{
gl_CurChunk = GLChunk::glObjectLabel;
glObjectLabel(eGL_BUFFER, ctxdata.m_ClientMemoryVBOs[i], -1,
StringFormat::Fmt("Client-memory pointer data (VB %zu)", i).c_str());
}
}
gl_CurChunk = GLChunk::glGenBuffers;
glGenBuffers(1, &ctxdata.m_ClientMemoryIBO);
gl_CurChunk = GLChunk::glBindBuffer;
glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ctxdata.m_ClientMemoryIBO);
GetResourceManager()->SetInternalResource(BufferRes(GetCtx(), ctxdata.m_ClientMemoryIBO));
gl_CurChunk = GLChunk::glBufferData;
glBufferData(eGL_ELEMENT_ARRAY_BUFFER, 64, NULL, eGL_DYNAMIC_DRAW);
if(HasExt[KHR_debug])
{
gl_CurChunk = GLChunk::glObjectLabel;
glObjectLabel(eGL_BUFFER, ctxdata.m_ClientMemoryIBO, -1, "Client-memory pointer data (IB)");
}
gl_CurChunk = GLChunk::glBindBuffer;
glBindBuffer(eGL_ARRAY_BUFFER, prevArrayBuffer);
gl_CurChunk = GLChunk::glBindBuffer;
glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, prevElementArrayBuffer);
}
// this is hack but GL context creation is an *utter mess*. For first-frame captures, only
// consider an attribs created context, to avoid starting capturing when the user is creating
// dummy contexts to be able to create the real one.
if(ctxdata.attribsCreate)
FirstFrame(ctxdata.ctx, (void *)winData.wnd);
}
struct ReplacementSearch
{
bool operator()(const rdcpair<ResourceId, Replacement> &a, ResourceId b) { return a.first < b; }
};
void WrappedOpenGL::ReplaceResource(ResourceId from, ResourceId to)
{
if(GetResourceManager()->HasLiveResource(from))
{
GLResource fromresource = GetResourceManager()->GetLiveResource(from);
GLResource toresource = GetResourceManager()->GetLiveResource(to);
// do actual replacement
if(fromresource.Namespace == toresource.Namespace)
{
GetResourceManager()->RemoveReplacement(from);
// if they're the same type we can just replace directly
GetResourceManager()->ReplaceResource(from, to);
}
else if(fromresource.Namespace == eResProgram && toresource.Namespace == eResShader)
{
// if we want to replace a program with a shader, this is a glCreateShaderProgramv so we need
// to handle it specially
ResourceId progsrcid = GetResourceManager()->GetLiveID(from);
const ProgramData &progdata = m_Programs[progsrcid];
// if this program has a replacement, remove it and delete the program generated for it
if(GetResourceManager()->HasReplacement(from))
{
glDeleteProgram(GetResourceManager()->GetLiveResource(from).name);
GetResourceManager()->RemoveReplacement(from);
}
GLuint progsrc = GetResourceManager()->GetLiveResource(from).name;
// make a new program
GLuint progdst = glCreateProgram();
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
// attach the shader
glAttachShader(progdst, GetResourceManager()->GetCurrentResource(to).name);
// mark separable
glProgramParameteri(progdst, eGL_PROGRAM_SEPARABLE, GL_TRUE);
// copy VS or FS bindings as necessary
ResourceId vs = progdata.stageShaders[0];
ResourceId fs = progdata.stageShaders[4];
if(vs != ResourceId())
CopyProgramAttribBindings(progsrc, progdst, &m_Shaders[vs].reflection);
if(fs != ResourceId())
CopyProgramFragDataBindings(progsrc, progdst, &m_Shaders[fs].reflection);
// link new program
glLinkProgram(progdst);
GLint status = 0;
glGetProgramiv(progdst, eGL_LINK_STATUS, &status);
if(status == 0)
{
GLint len = 1024;
glGetProgramiv(progdst, eGL_INFO_LOG_LENGTH, &len);
char *buffer = new char[len + 1];
glGetProgramInfoLog(progdst, len, NULL, buffer);
buffer[len] = 0;
RDCWARN(
"When making program replacement for glCreateShaderProgramv shader, program failed "
"to link. Skipping replacement:\n%s",
buffer);
delete[] buffer;
glDeleteProgram(progdst);
}
else
{
PerStageReflections dstStages;
FillReflectionArray(progdstid, dstStages);
std::map<GLint, GLint> translate;
PerStageReflections stages;
FillReflectionArray(progsrcid, stages);
// copy uniforms and set up new location translation table
CopyProgramUniforms(stages, progsrc, dstStages, progdst, &translate);
// start with the original location translation table, to account for any
// capture-replay translation
m_Programs[progdstid].locationTranslate = m_Programs[progsrcid].locationTranslate;
// compose on the one from editing.
for(auto lit = m_Programs[progdstid].locationTranslate.begin();
lit != m_Programs[progdstid].locationTranslate.end(); lit++)
{
auto lit2 = translate.find(lit->second);
if(lit2 != translate.end())
lit->second = lit2->second;
else
lit->second = -1;
}
// replace the program
GetResourceManager()->ReplaceResource(from, progdstid);
}
}
else
{
RDCERR("Unsupported replacement type from type %d to type %d", fromresource.Namespace,
toresource.Namespace);
}
RefreshDerivedReplacements();
}
}
void WrappedOpenGL::RemoveReplacement(ResourceId id)
{
if(GetResourceManager()->HasReplacement(id))
{
GetResourceManager()->RemoveReplacement(id);
RefreshDerivedReplacements();
}
}
void WrappedOpenGL::FreeTargetResource(ResourceId id)
{
if(GetResourceManager()->HasLiveResource(id))
{
GLResource resource = GetResourceManager()->GetLiveResource(id);
RDCASSERT(resource.Namespace != eResUnknown);
switch(resource.Namespace)
{
case eResShader: glDeleteShader(resource.name); break;
default: RDCERR("Unexpected resource type to be freed"); break;
}
}
}
void WrappedOpenGL::RefreshDerivedReplacements()
{
// we defer deletes of old replaced resources since it will invalidate elements in the vector
// we're iterating
rdcarray<GLuint> deletequeue;
// first go through programs and replace any that need to be updated based on whether they have
// any replaced shaders
for(auto it = m_Programs.begin(); it != m_Programs.end(); ++it)
{
ResourceId progsrcid = it->first;
const ProgramData &progdata = it->second;
ResourceId origsrcid = GetResourceManager()->GetOriginalID(progsrcid);
// only look at programs from the capture, no replay-time programs.
if(origsrcid == progsrcid)
continue;
// skip glCreateShaderProgramv programs. We handled this above and we don't want to try and
// create a dependent program or remove the replacement
if(progdata.shaderProgramUnlinkable)
continue;
// if this program has a replacement, remove it and delete the program generated for it
if(GetResourceManager()->HasReplacement(origsrcid))
{
deletequeue.push_back(GetResourceManager()->GetLiveResource(origsrcid).name);
GetResourceManager()->RemoveReplacement(origsrcid);
}
bool usesReplacedShader = false;
for(int i = 0; i < 6; i++)
{
if(GetResourceManager()->HasReplacement(
GetResourceManager()->GetOriginalID(progdata.stageShaders[i])))
{
usesReplacedShader = true;
break;
}
}
// if there are replaced shaders in use, create a new program with any/all replaced shaders.
if(usesReplacedShader)
{
GLuint progsrc = GetResourceManager()->GetCurrentResource(progsrcid).name;
// make a new program
GLuint progdst = glCreateProgram();
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
// attach shaders, going via the original ID to pick up replacements
for(int i = 0; i < 6; i++)
{
if(progdata.stageShaders[i] != ResourceId())
{
ResourceId shaderorigid = GetResourceManager()->GetOriginalID(progdata.stageShaders[i]);
glAttachShader(progdst, GetResourceManager()->GetLiveResource(shaderorigid).name);
}
}
// mark separable if previous program was separable
GLint sep = 0;
glGetProgramiv(progsrc, eGL_PROGRAM_SEPARABLE, &sep);
if(sep)
glProgramParameteri(progdst, eGL_PROGRAM_SEPARABLE, GL_TRUE);
ResourceId vs = progdata.stageShaders[0];
ResourceId fs = progdata.stageShaders[4];
if(vs != ResourceId())
CopyProgramAttribBindings(progsrc, progdst, &m_Shaders[vs].reflection);
if(fs != ResourceId())
CopyProgramFragDataBindings(progsrc, progdst, &m_Shaders[fs].reflection);
// link new program
glLinkProgram(progdst);
GLint status = 0;
glGetProgramiv(progdst, eGL_LINK_STATUS, &status);
if(status == 0)
{
GLint len = 1024;
glGetProgramiv(progdst, eGL_INFO_LOG_LENGTH, &len);
char *buffer = new char[len + 1];
glGetProgramInfoLog(progdst, len, NULL, buffer);
buffer[len] = 0;
RDCWARN(
"When making program replacement for shader, program failed to link. Skipping "
"replacement:\n%s",
buffer);
delete[] buffer;
glDeleteProgram(progdst);
}
else
{
PerStageReflections dstStages;
FillReflectionArray(progdstid, dstStages);
std::map<GLint, GLint> translate;
PerStageReflections stages;
FillReflectionArray(progsrcid, stages);
// copy uniforms and set up new location translation table
CopyProgramUniforms(stages, progsrc, dstStages, progdst, &translate);
// start with the original location translation table, to account for any
// capture-replay translation
m_Programs[progdstid].locationTranslate = m_Programs[progsrcid].locationTranslate;
// compose on the one from editing.
for(auto lit = m_Programs[progdstid].locationTranslate.begin();
lit != m_Programs[progdstid].locationTranslate.end(); lit++)
{
auto lit2 = translate.find(lit->second);
if(lit2 != translate.end())
lit->second = lit2->second;
else
lit->second = -1;
}
// replace the program
GetResourceManager()->ReplaceResource(origsrcid, progdstid);
}
}
}
for(GLuint prog : deletequeue)
glDeleteProgram(prog);
deletequeue.clear();
// then go through pipelines based on replaced programs, as above
for(auto it = m_Pipelines.begin(); it != m_Pipelines.end(); ++it)
{
ResourceId pipesrcid = it->first;
const PipelineData &pipedata = it->second;
ResourceId origsrcid = GetResourceManager()->GetOriginalID(pipesrcid);
// only look at programs from the capture, no replay-time programs.
if(origsrcid == pipesrcid)
continue;
// if this pipeline has a replacement, remove it and delete the pipeline generated for it
if(GetResourceManager()->HasReplacement(origsrcid))
{
deletequeue.push_back(GetResourceManager()->GetLiveResource(origsrcid).name);
GetResourceManager()->RemoveReplacement(origsrcid);
}
bool usesReplacedProgram = false;
for(int i = 0; i < 6; i++)
{
if(GetResourceManager()->HasReplacement(
GetResourceManager()->GetOriginalID(pipedata.stagePrograms[i])))
{
usesReplacedProgram = true;
break;
}
}
// if there are replaced shaders in use, create a new program with any/all replaced shaders.
if(usesReplacedProgram)
{
// make a new pipeline
GLuint pipedst = 0;
glGenProgramPipelines(1, &pipedst);
ResourceId pipedstid = GetResourceManager()->GetID(ProgramPipeRes(GetCtx(), pipedst));
// attach programs, going via the original ID to pick up replacements
for(int i = 0; i < 6; i++)
{
if(pipedata.stagePrograms[i] != ResourceId())
{
ResourceId progorigid = GetResourceManager()->GetOriginalID(pipedata.stagePrograms[i]);
glUseProgramStages(pipedst, ShaderBit(i),
GetResourceManager()->GetLiveResource(progorigid).name);
}
}
// replace the pipeline
GetResourceManager()->ReplaceResource(origsrcid, pipedstid);
}
}
for(GLuint prog : deletequeue)
glDeleteProgramPipelines(1, &prog);
deletequeue.clear();
}
void WrappedOpenGL::SwapBuffers(WindowingSystem winSystem, void *windowHandle)
{
if(IsBackgroundCapturing(m_State))
RenderDoc::Inst().Tick();
// don't do anything if no context is active.
if(m_ActiveContexts[Threading::GetCurrentID()].ctx == NULL)
{
m_NoCtxFrames++;
if(m_NoCtxFrames == 100)
{
RDCERR(
"Seen 100 frames with no context current. RenderDoc requires a context to be current "
"during the call to SwapBuffers to display its overlay and start/stop captures on "
"default keys.\nIf your GL use is elsewhere, consider using the in-application API to "
"trigger captures manually");
}
return;
}
m_NoCtxFrames = 0;
m_FrameCounter++; // first present becomes frame #1, this function is at the end of the frame
ContextData &ctxdata = GetCtxData();
// we only handle context-window associations here as it's too common to
// create invisible helper windows while creating contexts, that then
// become the default window.
// Since we only capture windows that do SwapBuffers (i.e. if you're doing
// headless rendering then you must capture via the API anyway), this
// isn't a big problem.
//
// Also we only set up associations for capturable windows.
if(ctxdata.Modern())
{
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
if(it->first != ctxdata.ctx)
it->second.UnassociateWindow(this, windowHandle);
ctxdata.AssociateWindow(this, winSystem, windowHandle);
}
// we used to do this here so it was as late as possible to avoid creating objects on contexts
// that might be shared later. wglShareLists requires contexts to have no objects and can be
// called after wglMakeCurrent. However we also need other objects like client-memory buffers and
// vendor checks inside makecurrent that it is not feasible to defer until later, since there's no
// other sync point after wglMakeCurrent before we'll need the information. So we don't support
// calling wglShareLists after wglMakeCurrent.
if(!ctxdata.ready)
ctxdata.CreateDebugData();
bool activeWindow = RenderDoc::Inst().IsActiveWindow(ctxdata.ctx, windowHandle);
// look at previous associations and decay any that are too old
uint64_t ref = Timing::GetUnixTimestamp() - 5; // 5 seconds
for(auto cit = m_ContextData.begin(); cit != m_ContextData.end(); ++cit)
{
for(auto wit = cit->second.windows.begin(); wit != cit->second.windows.end();)
{
if(wit->second.second < ref)
{
auto remove = wit;
++wit;
cit->second.UnassociateWindow(this, remove->first);
}
else
{
++wit;
}
}
}
if(IsBackgroundCapturing(m_State))
{
uint32_t overlay = RenderDoc::Inst().GetOverlayBits();
if(overlay & eRENDERDOC_Overlay_Enabled)
{
int flags = activeWindow ? RenderDoc::eOverlay_ActiveWindow : 0;
if(ctxdata.Legacy())
flags |= RenderDoc::eOverlay_CaptureDisabled;
rdcstr overlayText = RenderDoc::Inst().GetOverlayText(GetDriverType(), m_FrameCounter, flags);
if(ctxdata.Legacy())
{
if(!ctxdata.attribsCreate)
overlayText += "Context not created via CreateContextAttribs. Capturing disabled.\n";
overlayText += "Only OpenGL 3.2+ contexts are supported.\n";
}
else if(!ctxdata.isCore)
{
overlayText +=
"WARNING: Core profile not explicitly requested. Compatibility profile is not "
"supported.\n";
}
if(activeWindow && m_FailedFrame > 0)
{
const char *reasonString = "Unknown reason";
switch(m_FailedReason)
{
case CaptureFailed_UncappedUnmap: reasonString = "Uncapped Map()/Unmap()"; break;
default: break;
}
overlayText += StringFormat::Fmt("Failed capture at frame %d:\n", m_FailedFrame);
overlayText += StringFormat::Fmt(" %s\n", reasonString);
}
RenderText(0.0f, 0.0f, overlayText);
// swallow all errors we might have inadvertantly caused. This is
// better than letting an error propagate and maybe screw up the
// app (although it means we might swallow an error from before the
// SwapBuffers call, it can't be helped.
if(ctxdata.Legacy() && GL.glGetError)
ClearGLErrors();
}
}
if(IsActiveCapturing(m_State) && m_AppControlledCapture)
{
delete m_BackbufferImages[windowHandle];
m_BackbufferImages[windowHandle] = SaveBackbufferImage();
}
if(IsActiveCapturing(m_State) && gl_CurChunk != GLChunk::Max)
{
SERIALISE_TIME_CALL();
USE_SCRATCH_SERIALISER();
ser.SetDrawChunk();
SCOPED_SERIALISE_CHUNK(gl_CurChunk);
Serialise_Present(ser);
GetContextRecord()->AddChunk(scope.Get());
}
RenderDoc::Inst().AddActiveDriver(GetDriverType(), true);
if(!activeWindow)
return;
// only allow capturing on 'modern' created contexts
if(ctxdata.Legacy())
return;
// kill any current capture that isn't application defined
if(IsActiveCapturing(m_State) && !m_AppControlledCapture)
RenderDoc::Inst().EndFrameCapture(ctxdata.ctx, windowHandle);
if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && IsBackgroundCapturing(m_State))
{
RenderDoc::Inst().StartFrameCapture(ctxdata.ctx, windowHandle);
m_AppControlledCapture = false;
m_CapturedFrames.back().frameNumber = m_FrameCounter;
}
}
GLWindowingData *WrappedOpenGL::MakeValidContextCurrent(GLWindowingData existing,
GLWindowingData &newContext)
{
if(existing.ctx == NULL)
{
if(m_LastContexts.empty())
{
RDCERR("No GL context exists - can't make current, will likely crash");
return NULL;
}
// take the last context used
GLWindowingData ctx = m_LastContexts.back();
// and use the backdoor context on it
newContext = m_ContextData[ctx.ctx].shareGroup->m_BackDoor;
GLWindowingData *saved = new GLWindowingData;
m_ActiveContexts[Threading::GetCurrentID()] = newContext;
m_Platform.PushChildContext(existing, newContext, saved);
return saved;
}
return NULL;
}
void WrappedOpenGL::StartFrameCapture(void *dev, void *wnd)
{
if(!IsBackgroundCapturing(m_State))
return;
SCOPED_LOCK(glLock);
m_State = CaptureState::ActiveCapturing;
GetResourceManager()->ResetCaptureStartTime();
m_AppControlledCapture = true;
m_Failures = 0;
m_FailedFrame = 0;
m_FailedReason = CaptureSucceeded;
GLWindowingData existing = m_ActiveContexts[Threading::GetCurrentID()];
GLWindowingData newContext = existing;
GLWindowingData *pushChildSaved = MakeValidContextCurrent(existing, newContext);
FrameDescription frame;
frame.frameNumber = m_AppControlledCapture ? ~0U : m_FrameCounter;
frame.captureTime = Timing::GetUnixTimestamp();
RDCEraseEl(frame.stats);
m_CapturedFrames.push_back(frame);
GetResourceManager()->ClearReferencedResources();
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_PartialWrite);
GetResourceManager()->PrepareInitialContents();
FreeCaptureData();
AttemptCapture();
BeginCaptureFrame();
// serialise out the context configuration for this current context first
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::ContextConfiguration);
Serialise_ContextConfiguration(ser, GetCtx().ctx);
GetContextRecord()->AddChunk(scope.Get());
}
// if we changed contexts above, pop back to where we were
if(pushChildSaved)
{
m_Platform.PopChildContext(existing, newContext, *pushChildSaved);
delete pushChildSaved;
m_ActiveContexts[Threading::GetCurrentID()] = existing;
}
RDCLOG("Starting capture, frame %u", m_CapturedFrames.back().frameNumber);
}
bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd)
{
if(!IsActiveCapturing(m_State))
return true;
SCOPED_LOCK(glLock);
CaptureFailReason reason = CaptureSucceeded;
GLWindowingData existing = m_ActiveContexts[Threading::GetCurrentID()];
GLWindowingData newContext = existing;
GLWindowingData *pushChildSaved = MakeValidContextCurrent(existing, newContext);
if(HasSuccessfulCapture(reason))
{
RDCLOG("Finished capture, Frame %u", m_CapturedFrames.back().frameNumber);
m_Failures = 0;
m_FailedFrame = 0;
m_FailedReason = CaptureSucceeded;
ContextEndFrame();
FinishCapture();
RenderDoc::FramePixels *bbim = NULL;
// if the specified context isn't current, try and see if we've saved
// an appropriate backbuffer image during capture.
if((dev != NULL && existing.ctx != dev) || (wnd != 0 && (void *)existing.wnd != wnd))
{
auto it = m_BackbufferImages.find(wnd);
if(it != m_BackbufferImages.end())
{
// pop this backbuffer image out of the map
bbim = it->second;
m_BackbufferImages.erase(it);
}
}
// if we don't have one selected, save the backbuffer image from the
// current context
if(bbim == NULL)
bbim = SaveBackbufferImage();
RDCFile *rdc =
RenderDoc::Inst().CreateRDC(GetDriverType(), m_CapturedFrames.back().frameNumber, bbim[0]);
SAFE_DELETE(bbim);
for(auto it = m_BackbufferImages.begin(); it != m_BackbufferImages.end(); ++it)
delete it->second;
m_BackbufferImages.clear();
StreamWriter *captureWriter = NULL;
if(rdc)
{
SectionProperties props;
// Compress with LZ4 so that it's fast
props.flags = SectionFlags::LZ4Compressed;
props.version = m_SectionVersion;
props.type = SectionType::FrameCapture;
captureWriter = rdc->WriteSection(props);
}
else
{
captureWriter = new StreamWriter(StreamWriter::InvalidStream);
}
{
WriteSerialiser ser(captureWriter, Ownership::Stream);
ser.SetChunkMetadataRecording(m_ScratchSerialiser.GetChunkMetadataRecording());
ser.SetUserData(GetResourceManager());
{
// we no longer use this one, but for ease of compatibility we still serialise it here. This
// will be immediately overridden by the actual parameters by a
// GLChunk::ContextConfiguration chunk
GLInitParams init;
// store renderer and version, though we can't do any meaningful device selection
init.renderer = (const char *)GL.glGetString(eGL_RENDERER);
init.version = (const char *)GL.glGetString(eGL_VERSION);
SCOPED_SERIALISE_CHUNK(
SystemChunk::DriverInit,
sizeof(GLInitParams) + 16 + init.renderer.size() + init.version.size());
SERIALISE_ELEMENT(init);
}
{
// remember to update this estimated chunk length if you add more parameters
SCOPED_SERIALISE_CHUNK(GLChunk::DeviceInitialisation, 32);
// legacy behaviour where we had a single global VAO/FBO 0. Ignore, but preserve for easier
// compatibility with old captures
ResourceId vao, fbo;
SERIALISE_ELEMENT(vao);
SERIALISE_ELEMENT(fbo);
}
RDCDEBUG("Inserting Resource Serialisers");
GetResourceManager()->InsertReferencedChunks(ser);
GetResourceManager()->InsertInitialContentsChunks(ser);
RDCDEBUG("Creating Capture Scope");
GetResourceManager()->Serialise_InitialContentsNeeded(ser);
{
SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureScope, 16);
Serialise_CaptureScope(ser);
}
{
RDCDEBUG("Accumulating context resource list");
std::map<int32_t, Chunk *> recordlist;
m_ContextRecord->Insert(recordlist);
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
if(m_AcceptedCtx.empty() || m_AcceptedCtx.find(it->first) != m_AcceptedCtx.end())
{
GLResourceRecord *record = it->second.m_ContextDataRecord;
if(record)
{
RDCDEBUG("Getting Resource Record for context ID %s with %zu chunks",
ToStr(it->second.m_ContextDataResourceID).c_str(), record->NumChunks());
record->Insert(recordlist);
}
}
}
RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size());
float num = float(recordlist.size());
float idx = 0.0f;
for(auto it = recordlist.begin(); it != recordlist.end(); ++it)
{
RenderDoc::Inst().SetProgress(CaptureProgress::SerialiseFrameContents, idx / num);
idx += 1.0f;
it->second->Write(ser);
}
RDCDEBUG("Done");
}
}
RenderDoc::Inst().FinishCaptureWriting(rdc, m_CapturedFrames.back().frameNumber);
m_State = CaptureState::BackgroundCapturing;
GetResourceManager()->ResetLastWriteTimes();
GetResourceManager()->MarkUnwrittenResources();
GetResourceManager()->ClearReferencedResources();
GetResourceManager()->FreeInitialContents();
for(auto it = m_CoherentMaps.begin(); it != m_CoherentMaps.end(); ++it)
{
GLResourceRecord *record = *it;
record->FreeShadowStorage();
}
// if we changed contexts above, pop back to where we were
if(pushChildSaved)
{
m_Platform.PopChildContext(existing, newContext, *pushChildSaved);
delete pushChildSaved;
m_ActiveContexts[Threading::GetCurrentID()] = existing;
}
return true;
}
else
{
const char *reasonString = "Unknown reason";
switch(reason)
{
case CaptureFailed_UncappedUnmap: reasonString = "Uncapped Map()/Unmap()"; break;
default: break;
}
RDCLOG("Failed to capture, frame %u: %s", m_CapturedFrames.back().frameNumber, reasonString);
m_Failures++;
if((RenderDoc::Inst().GetOverlayBits() & eRENDERDOC_Overlay_Enabled))
{
ContextData &ctxdata = GetCtxData();
RenderText(0.0f, 0.0f, StringFormat::Fmt("Failed to capture frame %u: %s",
m_CapturedFrames.back().frameNumber, reasonString));
// swallow all errors we might have inadvertantly caused. This is
// better than letting an error propagate and maybe screw up the
// app (although it means we might swallow an error from before the
// SwapBuffers call, it can't be helped.
if(ctxdata.Legacy() && GL.glGetError)
ClearGLErrors();
}
uint32_t failedFrame = m_CapturedFrames.back().frameNumber;
m_CapturedFrames.back().frameNumber = m_AppControlledCapture ? ~0U : m_FrameCounter;
CleanupCapture();
GetResourceManager()->ClearReferencedResources();
GetResourceManager()->FreeInitialContents();
for(auto it = m_CoherentMaps.begin(); it != m_CoherentMaps.end(); ++it)
{
GLResourceRecord *record = *it;
record->FreeShadowStorage();
}
// if it's a capture triggered from application code, immediately
// give up as it's not reasonable to expect applications to detect and retry.
// otherwise we can retry in case the next frame works.
if(m_Failures > 5 || m_AppControlledCapture)
{
FinishCapture();
m_CapturedFrames.pop_back();
FreeCaptureData();
m_FailedFrame = failedFrame;
m_FailedReason = reason;
m_State = CaptureState::BackgroundCapturing;
GetResourceManager()->MarkUnwrittenResources();
}
else
{
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_PartialWrite);
GetResourceManager()->PrepareInitialContents();
AttemptCapture();
BeginCaptureFrame();
// serialise out the context configuration for this current context first
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(GLChunk::ContextConfiguration);
Serialise_ContextConfiguration(ser, GetCtx().ctx);
GetContextRecord()->AddChunk(scope.Get());
}
}
// if we changed contexts above, pop back to where we were
if(pushChildSaved)
{
m_Platform.PopChildContext(existing, newContext, *pushChildSaved);
delete pushChildSaved;
m_ActiveContexts[Threading::GetCurrentID()] = existing;
}
return false;
}
}
bool WrappedOpenGL::DiscardFrameCapture(void *dev, void *wnd)
{
if(!IsActiveCapturing(m_State))
return true;
SCOPED_LOCK(glLock);
RenderDoc::Inst().FinishCaptureWriting(NULL, m_CapturedFrames.back().frameNumber);
CleanupCapture();
GetResourceManager()->ClearReferencedResources();
GetResourceManager()->FreeInitialContents();
FinishCapture();
for(auto it = m_CoherentMaps.begin(); it != m_CoherentMaps.end(); ++it)
{
GLResourceRecord *record = *it;
record->FreeShadowStorage();
}
m_CapturedFrames.pop_back();
FreeCaptureData();
m_State = CaptureState::BackgroundCapturing;
GetResourceManager()->MarkUnwrittenResources();
for(auto it = m_BackbufferImages.begin(); it != m_BackbufferImages.end(); ++it)
delete it->second;
m_BackbufferImages.clear();
return true;
}
void WrappedOpenGL::FirstFrame(void *ctx, void *wndHandle)
{
// if we have to capture the first frame, begin capturing immediately
if(m_FrameCounter == 0 && IsBackgroundCapturing(m_State) &&
RenderDoc::Inst().ShouldTriggerCapture(0))
{
// since we haven't associated the window we can't capture by window, so we have to capture just
// on the device - the very next present to any window on this context will end the capture.
RenderDoc::Inst().StartFrameCapture(ctx, NULL);
m_AppControlledCapture = false;
m_CapturedFrames.back().frameNumber = 0;
}
}
RenderDoc::FramePixels *WrappedOpenGL::SaveBackbufferImage()
{
const uint16_t maxSize = 2048;
RenderDoc::FramePixels *fp = new RenderDoc::FramePixels();
if(GL.glGetIntegerv && GL.glReadBuffer && GL.glBindFramebuffer && GL.glBindBuffer && GL.glReadPixels)
{
RDCGLenum prevReadBuf = eGL_BACK;
GLint prevBuf = 0;
GLint packBufBind = 0;
GLint prevPackRowLen = 0;
GLint prevPackSkipRows = 0;
GLint prevPackSkipPixels = 0;
GLint prevPackAlignment = 0;
GL.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&prevReadBuf);
GL.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &prevBuf);
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, &packBufBind);
GL.glGetIntegerv(eGL_PACK_ROW_LENGTH, &prevPackRowLen);
GL.glGetIntegerv(eGL_PACK_SKIP_ROWS, &prevPackSkipRows);
GL.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &prevPackSkipPixels);
GL.glGetIntegerv(eGL_PACK_ALIGNMENT, &prevPackAlignment);
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0);
GL.glReadBuffer(eGL_BACK);
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
GL.glPixelStorei(eGL_PACK_ROW_LENGTH, 0);
GL.glPixelStorei(eGL_PACK_SKIP_ROWS, 0);
GL.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0);
GL.glPixelStorei(eGL_PACK_ALIGNMENT, 1);
ContextData &dat = GetCtxData();
fp->width = dat.initParams.width;
fp->height = dat.initParams.height;
fp->bpc = 1;
fp->stride = fp->bpc * 4;
fp->pitch = dat.initParams.width * fp->stride;
fp->max_width = maxSize;
fp->pitch_requirement = 4;
fp->len = (uint32_t)fp->pitch * fp->height;
fp->data = new uint8_t[fp->len];
fp->is_y_flipped = dat.initParams.isYFlipped;
// GLES only supports GL_RGBA
GL.glReadPixels(0, 0, fp->width, fp->height, eGL_RGBA, eGL_UNSIGNED_BYTE, fp->data);
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, packBufBind);
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevBuf);
GL.glReadBuffer(prevReadBuf);
GL.glPixelStorei(eGL_PACK_ROW_LENGTH, prevPackRowLen);
GL.glPixelStorei(eGL_PACK_SKIP_ROWS, prevPackSkipRows);
GL.glPixelStorei(eGL_PACK_SKIP_PIXELS, prevPackSkipPixels);
GL.glPixelStorei(eGL_PACK_ALIGNMENT, prevPackAlignment);
}
return fp;
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_Present(SerialiserType &ser)
{
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading() && IsLoading(m_State))
{
AddEvent();
DrawcallDescription draw;
GLuint col = 0;
GL.glGetNamedFramebufferAttachmentParameterivEXT(m_CurrentDefaultFBO, eGL_COLOR_ATTACHMENT0,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&col);
draw.copyDestination =
GetResourceManager()->GetOriginalID(GetResourceManager()->GetID(TextureRes(GetCtx(), col)));
draw.name =
StringFormat::Fmt("%s(%s)", ToStr(gl_CurChunk).c_str(), ToStr(draw.copyDestination).c_str());
draw.flags |= DrawFlags::Present;
AddDrawcall(draw, true);
}
return true;
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_CaptureScope(SerialiserType &ser)
{
SERIALISE_ELEMENT_LOCAL(frameNumber, m_CapturedFrames.back().frameNumber);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
GetReplay()->WriteFrameRecord().frameInfo.frameNumber = frameNumber;
RDCEraseEl(GetReplay()->WriteFrameRecord().frameInfo.stats);
}
return true;
}
bool WrappedOpenGL::Serialise_ContextInit(ReadSerialiser &ser)
{
SERIALISE_ELEMENT_LOCAL(FBO0_ID, ResourceId());
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
// this chunk has been replaced by the ContextConfiguration chunk. Previously this was used to
// register the ID of a framebuffer on another context, so it can be redirected to a single
// global FBO0. But now each context's FBO0 is unique. So if this is present, we also have the
// global FBO0 to redirect to.
ResourceId global_fbo0 = GetResourceManager()->GetID(FramebufferRes(GetCtx(), m_Global_FBO0));
GetReplay()->GetResourceDesc(global_fbo0).SetCustomName("Backbuffer FBO");
GetResourceManager()->ReplaceResource(FBO0_ID, global_fbo0);
AddResource(FBO0_ID, ResourceType::SwapchainImage, "");
GetReplay()->GetResourceDesc(FBO0_ID).SetCustomName("Window FBO");
// this is a hack, but we only support a single 'default' framebuffer so we set these
// replacements up as derived resources
GetReplay()->GetResourceDesc(global_fbo0).derivedResources.push_back(FBO0_ID);
GetReplay()->GetResourceDesc(FBO0_ID).parentResources.push_back(global_fbo0);
}
return true;
}
void WrappedOpenGL::ContextEndFrame()
{
USE_SCRATCH_SERIALISER();
ser.SetDrawChunk();
SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureEnd);
m_ContextRecord->AddChunk(scope.Get());
}
void WrappedOpenGL::CleanupResourceRecord(GLResourceRecord *record, bool freeParents)
{
if(record)
{
record->LockChunks();
while(record->HasChunks())
{
Chunk *chunk = record->GetLastChunk();
SAFE_DELETE(chunk);
record->PopChunk();
}
record->UnlockChunks();
if(freeParents)
record->FreeParents(GetResourceManager());
}
}
void WrappedOpenGL::CleanupCapture()
{
m_SuccessfulCapture = true;
m_FailureReason = CaptureSucceeded;
CleanupResourceRecord(m_ContextRecord, true);
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
CleanupResourceRecord(it->second.m_ContextDataRecord, true);
}
}
void WrappedOpenGL::FreeCaptureData()
{
}
void WrappedOpenGL::QueuePrepareInitialState(GLResource res)
{
QueuedResource q;
q.res = res;
auto insertPos = std::lower_bound(m_QueuedInitialFetches.begin(), m_QueuedInitialFetches.end(), q);
m_QueuedInitialFetches.insert(insertPos - m_QueuedInitialFetches.begin(), q);
}
void WrappedOpenGL::QueueResourceRelease(GLResource res)
{
QueuedResource q;
q.res = res;
auto insertPos = std::lower_bound(m_QueuedReleases.begin(), m_QueuedReleases.end(), q);
m_QueuedReleases.insert(insertPos - m_QueuedReleases.begin(), q);
}
void WrappedOpenGL::CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint,
GLenum textype, GLint dim, GLint width, GLint height,
GLint depth, GLint samples, int mips)
{
if(textype == eGL_TEXTURE_BUFFER)
{
return;
}
GLuint ppb = 0, pub = 0;
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb);
GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub);
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0);
if(textype == eGL_TEXTURE_2D_MULTISAMPLE)
{
// we need a sized format for storage functions
internalFormat = GetSizedFormat(internalFormat);
GL.glTextureStorage2DMultisampleEXT(tex, textype, samples, internalFormat, width, height,
GL_TRUE);
}
else if(textype == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY)
{
// we need a sized format for storage functions
internalFormat = GetSizedFormat(internalFormat);
GL.glTextureStorage3DMultisampleEXT(tex, textype, samples, internalFormat, width, height, depth,
GL_TRUE);
}
else
{
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAX_LEVEL, mips - 1);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
bool isCompressed = IsCompressedFormat(internalFormat);
GLenum baseFormat = eGL_RGBA;
GLenum dataType = internalFormatHint != eGL_NONE ? internalFormatHint : eGL_UNSIGNED_BYTE;
if(!isCompressed)
{
baseFormat = GetBaseFormat(internalFormat);
if(internalFormatHint == eGL_NONE)
dataType = GetDataType(internalFormat);
}
GLenum targets[] = {
eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X,
eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
};
int count = ARRAY_COUNT(targets);
if(textype != eGL_TEXTURE_CUBE_MAP)
{
targets[0] = textype;
count = 1;
}
GLsizei w = (GLsizei)width;
GLsizei h = (GLsizei)height;
GLsizei d = (GLsizei)depth;
for(int m = 0; m < mips; m++)
{
for(int t = 0; t < count; t++)
{
if(isCompressed)
{
GLsizei compSize = (GLsizei)GetCompressedByteSize(w, h, d, internalFormat);
bytebuf dummy;
dummy.resize(compSize);
if(dim == 1)
GL.glCompressedTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, compSize,
&dummy[0]);
else if(dim == 2)
GL.glCompressedTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, compSize,
&dummy[0]);
else if(dim == 3)
GL.glCompressedTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0,
compSize, &dummy[0]);
}
else
{
if(dim == 1)
GL.glTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, baseFormat, dataType,
NULL);
else if(dim == 2)
GL.glTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, baseFormat,
dataType, NULL);
else if(dim == 3)
GL.glTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, baseFormat,
dataType, NULL);
}
}
w = RDCMAX(1, w >> 1);
if(textype != eGL_TEXTURE_1D_ARRAY)
h = RDCMAX(1, h >> 1);
if(textype != eGL_TEXTURE_2D_ARRAY && textype != eGL_TEXTURE_CUBE_MAP_ARRAY)
d = RDCMAX(1, d >> 1);
}
}
if(IsCaptureMode(m_State))
{
// register this texture and set up its texture details, so it's available for emulation
// readback.
GLResource res = TextureRes(GetCtx(), tex);
ResourceId id = GetResourceManager()->RegisterResource(res);
WrappedOpenGL::TextureData &details = m_Textures[id];
details.resource = res;
details.curType = textype;
details.dimension = dim;
details.emulated = details.view = false;
details.width = width;
details.height = height;
details.depth = depth;
details.samples = samples;
details.creationFlags = TextureCategory::NoFlags;
details.internalFormat = internalFormat;
details.mipsValid = (1 << mips) - 1;
}
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub);
}
void WrappedOpenGL::ReleaseResource(GLResource res)
{
switch(res.Namespace)
{
default: RDCERR("Unknown namespace to release: %s", ToStr(res.Namespace).c_str()); return;
case eResTexture: GL.glDeleteTextures(1, &res.name); break;
case eResSampler: GL.glDeleteSamplers(1, &res.name); break;
case eResFramebuffer: GL.glDeleteFramebuffers(1, &res.name); break;
case eResRenderbuffer: GL.glDeleteRenderbuffers(1, &res.name); break;
case eResBuffer: GL.glDeleteBuffers(1, &res.name); break;
case eResVertexArray: GL.glDeleteVertexArrays(1, &res.name); break;
case eResShader: GL.glDeleteShader(res.name); break;
case eResProgram: GL.glDeleteProgram(res.name); break;
case eResProgramPipe: GL.glDeleteProgramPipelines(1, &res.name); break;
case eResFeedback: GL.glDeleteTransformFeedbacks(1, &res.name); break;
case eResQuery: GL.glDeleteQueries(1, &res.name); break;
case eResSync: GL.glDeleteSync(GetResourceManager()->GetSync(res.name)); break;
case eResExternalMemory: GL.glDeleteMemoryObjectsEXT(1, &res.name); break;
case eResExternalSemaphore: GL.glDeleteSemaphoresEXT(1, &res.name); break;
}
}
void WrappedOpenGL::AttemptCapture()
{
m_State = CaptureState::ActiveCapturing;
m_DebugMessages.clear();
if(!HasExt[KHR_debug] && RenderDoc::Inst().GetCaptureOptions().apiValidation)
{
DebugMessage msg = {};
msg.category = MessageCategory::Portability;
msg.severity = MessageSeverity::High;
msg.source = MessageSource::RuntimeWarning;
msg.description =
"API Validation was enabled, but KHR_debug was not available in this driver so no "
"validation messages could be retrieved";
m_DebugMessages.push_back(msg);
}
{
RDCDEBUG("GL Context %s Attempting capture", ToStr(m_ContextResourceID).c_str());
m_SuccessfulCapture = true;
m_FailureReason = CaptureSucceeded;
CleanupResourceRecord(m_ContextRecord, false);
for(auto it = m_ContextData.begin(); it != m_ContextData.end(); ++it)
{
CleanupResourceRecord(it->second.m_ContextDataRecord, false);
}
}
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_BeginCaptureFrame(SerialiserType &ser)
{
GLRenderState state;
if(ser.IsWriting())
{
state.FetchState(this);
state.MarkReferenced(this, true);
}
SERIALISE_ELEMENT(state);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
rdcarray<DebugMessage> savedDebugMessages;
// save any debug messages we built up
savedDebugMessages.swap(m_DebugMessages);
state.ApplyState(this);
// restore saved messages - which implicitly discards any generated while applying state
savedDebugMessages.swap(m_DebugMessages);
}
return true;
}
void WrappedOpenGL::BeginCaptureFrame()
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureBegin);
Serialise_BeginCaptureFrame(ser);
m_ContextRecord->AddChunk(scope.Get(), 1);
// mark VAO 0 on this context as referenced
{
GLuint prevVAO = 0;
GL.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&prevVAO);
GL.glBindVertexArray(0);
GetResourceManager()->MarkVAOReferenced(VertexArrayRes(GetCtx(), 0), eFrameRef_PartialWrite,
true);
GL.glBindVertexArray(prevVAO);
}
}
void WrappedOpenGL::FinishCapture()
{
m_State = CaptureState::BackgroundCapturing;
m_DebugMessages.clear();
// m_SuccessfulCapture = false;
}
void WrappedOpenGL::AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d)
{
if(IsLoading(m_State) || src == MessageSource::RuntimeWarning)
{
DebugMessage msg;
msg.eventId = m_CurEventID;
msg.messageID = 0;
msg.source = src;
msg.category = c;
msg.severity = sv;
msg.description = d;
m_DebugMessages.push_back(msg);
}
}
rdcarray<DebugMessage> WrappedOpenGL::GetDebugMessages()
{
rdcarray<DebugMessage> ret;
ret.swap(m_DebugMessages);
return ret;
}
template <typename SerialiserType>
void WrappedOpenGL::Serialise_DebugMessages(SerialiserType &ser)
{
rdcarray<DebugMessage> DebugMessages;
if(ser.IsWriting())
{
DebugMessages.swap(m_DebugMessages);
}
SERIALISE_ELEMENT(DebugMessages);
// if we're using replay-time API validation, fetch messages at replay time and ignore any
// serialised ones
if(ser.IsReading() && IsLoading(m_State) && m_ReplayOptions.apiValidation)
{
DebugMessages = m_DebugMessages;
m_DebugMessages.clear();
}
// hide empty sets of messages.
if(ser.IsReading() && DebugMessages.empty())
ser.Hidden();
if(ser.IsReading() && IsLoading(m_State))
{
for(DebugMessage &msg : DebugMessages)
{
msg.eventId = m_CurEventID;
AddDebugMessage(msg);
}
}
}
template void WrappedOpenGL::Serialise_DebugMessages(WriteSerialiser &ser);
template void WrappedOpenGL::Serialise_DebugMessages(ReadSerialiser &ser);
bool WrappedOpenGL::RecordUpdateCheck(GLResourceRecord *record)
{
// if nothing is bound, don't serialise chunk
if(record == NULL)
return false;
// if we've already stopped tracking this object, return as such
if(record->UpdateCount > 64)
return false;
// increase update count
record->UpdateCount++;
// if update count is high, mark as dirty
if(record->UpdateCount > 64)
{
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
return false;
}
return true;
}
void WrappedOpenGL::RegisterDebugCallback()
{
// once GL driver is more tested, this can be disabled
if(HasExt[KHR_debug] && GL.glDebugMessageCallback)
{
GL.glDebugMessageCallback(&DebugSnoopStatic, this);
GL.glEnable(eGL_DEBUG_OUTPUT_SYNCHRONOUS);
}
}
void WrappedOpenGL::DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar *message)
{
if(type != eGL_DEBUG_TYPE_PUSH_GROUP && type != eGL_DEBUG_TYPE_POP_GROUP &&
type != eGL_DEBUG_TYPE_MARKER)
{
if(type != eGL_DEBUG_TYPE_PERFORMANCE && type != eGL_DEBUG_TYPE_OTHER)
{
RDCLOG("Got a Debug message from %s, type %s, ID %d, severity %s:\n'%s'",
ToStr(source).c_str(), ToStr(type).c_str(), id, ToStr(severity).c_str(), message);
if(m_DebugMsgContext != "")
RDCLOG("Debug Message context: \"%s\"", m_DebugMsgContext.c_str());
}
if(IsActiveCapturing(m_State) || (IsLoading(m_State) && m_ReplayOptions.apiValidation))
{
DebugMessage msg;
msg.eventId = 0;
msg.messageID = id;
msg.description = rdcstr(message, length);
msg.source = MessageSource::API;
switch(severity)
{
case eGL_DEBUG_SEVERITY_HIGH: msg.severity = MessageSeverity::High; break;
case eGL_DEBUG_SEVERITY_MEDIUM: msg.severity = MessageSeverity::Medium; break;
case eGL_DEBUG_SEVERITY_LOW: msg.severity = MessageSeverity::Low; break;
case eGL_DEBUG_SEVERITY_NOTIFICATION:
default: msg.severity = MessageSeverity::Info; break;
}
if(source == eGL_DEBUG_SOURCE_APPLICATION)
{
msg.category = MessageCategory::Application_Defined;
}
else if(source == eGL_DEBUG_SOURCE_SHADER_COMPILER)
{
msg.category = MessageCategory::Shaders;
}
else
{
switch(type)
{
case eGL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
msg.category = MessageCategory::Deprecated;
break;
case eGL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: msg.category = MessageCategory::Undefined; break;
case eGL_DEBUG_TYPE_PORTABILITY: msg.category = MessageCategory::Portability; break;
case eGL_DEBUG_TYPE_PERFORMANCE: msg.category = MessageCategory::Performance; break;
case eGL_DEBUG_TYPE_ERROR:
case eGL_DEBUG_TYPE_OTHER:
default: msg.category = MessageCategory::Miscellaneous; break;
}
}
m_DebugMessages.push_back(msg);
}
}
if(GetCtxData().m_RealDebugFunc && !RenderDoc::Inst().GetCaptureOptions().debugOutputMute)
GetCtxData().m_RealDebugFunc(source, type, id, severity, length, message,
GetCtxData().m_RealDebugFuncParam);
}
void WrappedOpenGL::AddResource(ResourceId id, ResourceType type, const char *defaultNamePrefix)
{
ResourceDescription &descr = GetReplay()->GetResourceDesc(id);
uint64_t num;
memcpy(&num, &id, sizeof(uint64_t));
descr.name = defaultNamePrefix + (" " + ToStr(num));
descr.autogeneratedName = true;
descr.type = type;
AddResourceCurChunk(descr);
}
void WrappedOpenGL::DerivedResource(GLResource parent, ResourceId child)
{
ResourceId parentId = GetResourceManager()->GetOriginalID(GetResourceManager()->GetID(parent));
GetReplay()->GetResourceDesc(parentId).derivedResources.push_back(child);
GetReplay()->GetResourceDesc(child).parentResources.push_back(parentId);
}
void WrappedOpenGL::AddResourceCurChunk(ResourceDescription &descr)
{
descr.initialisationChunks.push_back((uint32_t)m_StructuredFile->chunks.size() - 1);
}
void WrappedOpenGL::AddResourceCurChunk(ResourceId id)
{
AddResourceCurChunk(GetReplay()->GetResourceDesc(id));
}
void WrappedOpenGL::AddResourceInitChunk(GLResource res)
{
// don't add chunks that were recorded (some chunks are ambiguous)
if(m_CurEventID == 0)
{
GLResourceManager *rm = GetResourceManager();
AddResourceCurChunk(rm->GetOriginalID(rm->GetID(res)));
}
}
bool WrappedOpenGL::HasNonDebugMarkers()
{
for(const APIEvent &ev : m_CurEvents)
{
GLChunk chunk = (GLChunk)m_StructuredFile->chunks[ev.chunkIndex]->metadata.chunkID;
if(chunk != GLChunk::glPushGroupMarkerEXT && chunk != GLChunk::glPopGroupMarkerEXT &&
chunk != GLChunk::glPushDebugGroupKHR && chunk != GLChunk::glPopDebugGroupKHR &&
chunk != GLChunk::glPushDebugGroup && chunk != GLChunk::glPopDebugGroup)
return true;
}
return false;
}
ReplayStatus WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
{
int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture);
if(sectionIdx < 0)
return ReplayStatus::FileCorrupted;
StreamReader *reader = rdc->ReadSection(sectionIdx);
if(reader->IsErrored())
{
delete reader;
return ReplayStatus::FileIOFailed;
}
ReadSerialiser ser(reader, Ownership::Stream);
ser.SetStringDatabase(&m_StringDB);
ser.SetUserData(GetResourceManager());
ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers);
m_StructuredFile = &ser.GetStructuredFile();
m_StoredStructuredData.version = m_StructuredFile->version = m_SectionVersion;
ser.SetVersion(m_SectionVersion);
int chunkIdx = 0;
struct chunkinfo
{
chunkinfo() : count(0), totalsize(0), total(0.0) {}
int count;
uint64_t totalsize;
double total;
};
std::map<GLChunk, chunkinfo> chunkInfos;
SCOPED_TIMER("chunk initialisation");
uint64_t frameDataSize = 0;
for(;;)
{
PerformanceTimer timer;
uint64_t offsetStart = reader->GetOffset();
GLChunk context = ser.ReadChunk<GLChunk>();
chunkIdx++;
if(reader->IsErrored())
return ReplayStatus::APIDataCorrupted;
bool success = ProcessChunk(ser, context);
ser.EndChunk();
if(reader->IsErrored())
return ReplayStatus::APIDataCorrupted;
// if there wasn't a serialisation error, but the chunk didn't succeed, then it's an API replay
// failure.
if(!success)
return m_FailedReplayStatus;
uint64_t offsetEnd = reader->GetOffset();
RenderDoc::Inst().SetProgress(LoadProgress::FileInitialRead,
float(offsetEnd) / float(reader->GetSize()));
if((SystemChunk)context == SystemChunk::CaptureScope)
{
GetReplay()->WriteFrameRecord().frameInfo.fileOffset = offsetStart;
// read the remaining data into memory and pass to immediate context
frameDataSize = reader->GetSize() - reader->GetOffset();
m_FrameReader = new StreamReader(reader, frameDataSize);
rdcarray<DebugMessage> savedDebugMessages;
// save any debug messages we built up
savedDebugMessages.swap(m_DebugMessages);
GetResourceManager()->ApplyInitialContents();
// restore saved messages - which implicitly discards any generated while applying initial
// contents
savedDebugMessages.swap(m_DebugMessages);
ReplayStatus status = ContextReplayLog(m_State, 0, 0, false);
if(status != ReplayStatus::Succeeded)
return status;
}
chunkInfos[context].total += timer.GetMilliseconds();
chunkInfos[context].totalsize += offsetEnd - offsetStart;
chunkInfos[context].count++;
if((SystemChunk)context == SystemChunk::CaptureScope || reader->IsErrored() || reader->AtEnd())
break;
}
#if ENABLED(RDOC_DEVEL)
for(auto it = chunkInfos.begin(); it != chunkInfos.end(); ++it)
{
double dcount = double(it->second.count);
RDCDEBUG(
"% 5d chunks - Time: %9.3fms total/%9.3fms avg - Size: %8.3fMB total/%7.3fMB avg - %s (%u)",
it->second.count, it->second.total, it->second.total / dcount,
double(it->second.totalsize) / (1024.0 * 1024.0),
double(it->second.totalsize) / (dcount * 1024.0 * 1024.0),
GetChunkName((uint32_t)it->first).c_str(), uint32_t(it->first));
}
#endif
// steal the structured data for ourselves
m_StructuredFile->Swap(m_StoredStructuredData);
// and in future use this file.
m_StructuredFile = &m_StoredStructuredData;
GetReplay()->WriteFrameRecord().frameInfo.uncompressedFileSize =
rdc->GetSectionProperties(sectionIdx).uncompressedSize;
GetReplay()->WriteFrameRecord().frameInfo.compressedFileSize =
rdc->GetSectionProperties(sectionIdx).compressedSize;
GetReplay()->WriteFrameRecord().frameInfo.persistentSize = frameDataSize;
GetReplay()->WriteFrameRecord().frameInfo.initDataSize =
chunkInfos[(GLChunk)SystemChunk::InitialContents].totalsize;
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
GetReplay()->WriteFrameRecord().frameInfo.persistentSize);
return ReplayStatus::Succeeded;
}
bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk)
{
gl_CurChunk = chunk;
// there are unfortunately too many special cases with serialisation to be able to re-use the hook
// definition macros here. Aliases forward to their 'real' functions, but we also share
// serialisation between EXT_dsa, ARB_dsa and non-dsa functions. Likewise for the horrible
// glUniform variants where there are loads of functions that serialise the same way with slight
// type differences.
// we handle this here as we don't want a default: in the switch() below - that means we get a
// warning if any GL chunk is missed.
{
SystemChunk system = (SystemChunk)chunk;
if(system == SystemChunk::DriverInit)
{
GLInitParams InitParams;
SERIALISE_ELEMENT(InitParams);
SERIALISE_CHECK_READ_ERRORS();
m_InitChunkIndex = (uint32_t)m_StructuredFile->chunks.size() - 1;
return true;
}
else if(system == SystemChunk::InitialContentsList)
{
GetResourceManager()->CreateInitialContents(ser);
SERIALISE_CHECK_READ_ERRORS();
return true;
}
else if(system == SystemChunk::InitialContents)
{
return GetResourceManager()->Serialise_InitialState(ser, ResourceId(), NULL, NULL);
}
else if(system == SystemChunk::CaptureScope)
{
return Serialise_CaptureScope(ser);
}
else if(system == SystemChunk::CaptureEnd)
{
bool lastSwap =
m_LastChunk == GLChunk::SwapBuffers || m_LastChunk == GLChunk::wglSwapBuffers ||
m_LastChunk == GLChunk::glXSwapBuffers || m_LastChunk == GLChunk::CGLFlushDrawable ||
m_LastChunk == GLChunk::eglSwapBuffers || m_LastChunk == GLChunk::eglPostSubBufferNV ||
m_LastChunk == GLChunk::eglSwapBuffersWithDamageEXT ||
m_LastChunk == GLChunk::eglSwapBuffersWithDamageKHR;
if(IsLoading(m_State) && !lastSwap)
{
AddEvent();
DrawcallDescription draw;
draw.name = "End of Capture";
draw.flags |= DrawFlags::Present;
GLuint col = 0;
GL.glGetNamedFramebufferAttachmentParameterivEXT(m_CurrentDefaultFBO, eGL_COLOR_ATTACHMENT0,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&col);
draw.copyDestination = GetResourceManager()->GetOriginalID(
GetResourceManager()->GetID(TextureRes(GetCtx(), col)));
AddDrawcall(draw, true);
}
return true;
}
else if(system < SystemChunk::FirstDriverChunk)
{
RDCERR("Unexpected system chunk in capture data: %u", system);
ser.SkipCurrentChunk();
SERIALISE_CHECK_READ_ERRORS();
return true;
}
}
switch(chunk)
{
case GLChunk::DeviceInitialisation:
{
ResourceId vao, fbo;
SERIALISE_ELEMENT(vao).Hidden();
SERIALISE_ELEMENT(fbo).Named("FBO 0 ID"_lit);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
// legacy behaviour where we had a single global VAO 0. Create a corresponding VAO so that
// it can be bound and have initial contents applied to it
if(vao != ResourceId())
{
glGenVertexArrays(1, &m_Global_VAO0);
glBindVertexArray(m_Global_VAO0);
GetResourceManager()->AddLiveResource(vao, VertexArrayRes(GetCtx(), m_Global_VAO0));
AddResource(vao, ResourceType::StateObject, "Vertex Array");
GetReplay()->GetResourceDesc(vao).SetCustomName("Default VAO");
GetReplay()->GetResourceDesc(vao).initialisationChunks.push_back(m_InitChunkIndex);
}
// similar behaviour for a single global FBO 0.
if(fbo != ResourceId())
CreateReplayBackbuffer(m_GlobalInitParams, fbo, m_Global_FBO0, "Backbuffer");
}
return true;
}
case GLChunk::glContextInit: return Serialise_ContextInit(ser);
case GLChunk::glGenBuffersARB:
case GLChunk::glGenBuffers: return Serialise_glGenBuffers(ser, 0, 0);
case GLChunk::glCreateBuffers: return Serialise_glCreateBuffers(ser, 0, 0);
case GLChunk::glBufferStorage:
case GLChunk::glBufferStorageEXT:
case GLChunk::glNamedBufferStorage:
case GLChunk::glNamedBufferStorageEXT:
return Serialise_glNamedBufferStorageEXT(ser, 0, 0, 0, 0);
case GLChunk::glBufferData:
case GLChunk::glBufferDataARB:
case GLChunk::glNamedBufferData:
case GLChunk::glNamedBufferDataEXT:
return Serialise_glNamedBufferDataEXT(ser, 0, 0, 0, eGL_NONE);
case GLChunk::glBufferSubData:
case GLChunk::glBufferSubDataARB:
case GLChunk::glNamedBufferSubData:
case GLChunk::glNamedBufferSubDataEXT:
return Serialise_glNamedBufferSubDataEXT(ser, 0, 0, 0, 0);
case GLChunk::glCopyBufferSubData:
case GLChunk::glCopyNamedBufferSubData:
case GLChunk::glNamedCopyBufferSubDataEXT:
return Serialise_glNamedCopyBufferSubDataEXT(ser, 0, 0, 0, 0, 0);
case GLChunk::glBindBufferARB:
case GLChunk::glBindBuffer: return Serialise_glBindBuffer(ser, eGL_NONE, 0);
case GLChunk::glBindBufferBaseEXT:
case GLChunk::glBindBufferBase: return Serialise_glBindBufferBase(ser, eGL_NONE, 0, 0);
case GLChunk::glBindBufferRangeEXT:
case GLChunk::glBindBufferRange: return Serialise_glBindBufferRange(ser, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glBindBuffersBase: return Serialise_glBindBuffersBase(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glBindBuffersRange:
return Serialise_glBindBuffersRange(ser, eGL_NONE, 0, 0, 0, 0, 0);
case GLChunk::glUnmapBuffer:
case GLChunk::glUnmapBufferARB:
case GLChunk::glUnmapBufferOES:
case GLChunk::glUnmapNamedBuffer:
case GLChunk::glUnmapNamedBufferEXT: return Serialise_glUnmapNamedBufferEXT(ser, 0);
case GLChunk::CoherentMapWrite:
case GLChunk::glFlushMappedBufferRange:
case GLChunk::glFlushMappedNamedBufferRange:
case GLChunk::glFlushMappedNamedBufferRangeEXT:
return Serialise_glFlushMappedNamedBufferRangeEXT(ser, 0, 0, 0);
case GLChunk::glGenTransformFeedbacks: return Serialise_glGenTransformFeedbacks(ser, 0, 0);
case GLChunk::glCreateTransformFeedbacks:
return Serialise_glCreateTransformFeedbacks(ser, 0, 0);
case GLChunk::glTransformFeedbackBufferBase:
return Serialise_glTransformFeedbackBufferBase(ser, 0, 0, 0);
case GLChunk::glTransformFeedbackBufferRange:
return Serialise_glTransformFeedbackBufferRange(ser, 0, 0, 0, 0, 0);
case GLChunk::glBindTransformFeedback:
return Serialise_glBindTransformFeedback(ser, eGL_NONE, 0);
case GLChunk::glBeginTransformFeedbackEXT:
case GLChunk::glBeginTransformFeedback:
return Serialise_glBeginTransformFeedback(ser, eGL_NONE);
case GLChunk::glPauseTransformFeedback: return Serialise_glPauseTransformFeedback(ser);
case GLChunk::glResumeTransformFeedback: return Serialise_glResumeTransformFeedback(ser);
case GLChunk::glEndTransformFeedbackEXT:
case GLChunk::glEndTransformFeedback: return Serialise_glEndTransformFeedback(ser);
case GLChunk::glVertexAttribPointer:
case GLChunk::glVertexAttribPointerARB:
case GLChunk::glVertexArrayVertexAttribOffsetEXT:
return Serialise_glVertexArrayVertexAttribOffsetEXT(ser, 0, 0, 0, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glVertexAttribIPointer:
case GLChunk::glVertexAttribIPointerEXT:
case GLChunk::glVertexArrayVertexAttribIOffsetEXT:
return Serialise_glVertexArrayVertexAttribIOffsetEXT(ser, 0, 0, 0, 0, eGL_NONE, 0, 0);
case GLChunk::glVertexAttribLPointer:
case GLChunk::glVertexAttribLPointerEXT:
case GLChunk::glVertexArrayVertexAttribLOffsetEXT:
return Serialise_glVertexArrayVertexAttribLOffsetEXT(ser, 0, 0, 0, 0, eGL_NONE, 0, 0);
case GLChunk::glVertexAttribBinding:
case GLChunk::glVertexArrayAttribBinding:
case GLChunk::glVertexArrayVertexAttribBindingEXT:
return Serialise_glVertexArrayVertexAttribBindingEXT(ser, 0, 0, 0);
case GLChunk::glVertexAttribFormat:
case GLChunk::glVertexArrayAttribFormat:
case GLChunk::glVertexArrayVertexAttribFormatEXT:
return Serialise_glVertexArrayVertexAttribFormatEXT(ser, 0, 0, 0, eGL_NONE, 0, 0);
case GLChunk::glVertexAttribIFormat:
case GLChunk::glVertexArrayAttribIFormat:
case GLChunk::glVertexArrayVertexAttribIFormatEXT:
return Serialise_glVertexArrayVertexAttribIFormatEXT(ser, 0, 0, 0, eGL_NONE, 0);
case GLChunk::glVertexAttribLFormat:
case GLChunk::glVertexArrayAttribLFormat:
case GLChunk::glVertexArrayVertexAttribLFormatEXT:
return Serialise_glVertexArrayVertexAttribLFormatEXT(ser, 0, 0, 0, eGL_NONE, 0);
case GLChunk::glVertexAttribDivisor:
case GLChunk::glVertexAttribDivisorARB:
case GLChunk::glVertexArrayVertexAttribDivisorEXT:
return Serialise_glVertexArrayVertexAttribDivisorEXT(ser, 0, 0, 0);
case GLChunk::glEnableVertexAttribArray:
case GLChunk::glEnableVertexAttribArrayARB:
case GLChunk::glEnableVertexArrayAttrib:
case GLChunk::glEnableVertexArrayAttribEXT:
return Serialise_glEnableVertexArrayAttribEXT(ser, 0, 0);
case GLChunk::glDisableVertexAttribArray:
case GLChunk::glDisableVertexAttribArrayARB:
case GLChunk::glDisableVertexArrayAttrib:
case GLChunk::glDisableVertexArrayAttribEXT:
return Serialise_glDisableVertexArrayAttribEXT(ser, 0, 0);
case GLChunk::glGenVertexArraysOES:
case GLChunk::glGenVertexArrays: return Serialise_glGenVertexArrays(ser, 0, 0);
case GLChunk::glCreateVertexArrays: return Serialise_glCreateVertexArrays(ser, 0, 0);
case GLChunk::glBindVertexArrayOES:
case GLChunk::glBindVertexArray: return Serialise_glBindVertexArray(ser, 0);
case GLChunk::glVertexArrayElementBuffer:
return Serialise_glVertexArrayElementBuffer(ser, 0, 0);
case GLChunk::glBindVertexBuffer:
case GLChunk::glVertexArrayVertexBuffer:
case GLChunk::glVertexArrayBindVertexBufferEXT:
return Serialise_glVertexArrayBindVertexBufferEXT(ser, 0, 0, 0, 0, 0);
case GLChunk::glBindVertexBuffers:
case GLChunk::glVertexArrayVertexBuffers:
return Serialise_glVertexArrayVertexBuffers(ser, 0, 0, 0, 0, 0, 0);
case GLChunk::glVertexBindingDivisor:
case GLChunk::glVertexArrayBindingDivisor:
case GLChunk::glVertexArrayVertexBindingDivisorEXT:
return Serialise_glVertexArrayVertexBindingDivisorEXT(ser, 0, 0, 0);
case GLChunk::glVertexAttrib1d:
case GLChunk::glVertexAttrib1dARB:
case GLChunk::glVertexAttrib1dv:
case GLChunk::glVertexAttrib1dvARB:
case GLChunk::glVertexAttrib1f:
case GLChunk::glVertexAttrib1fARB:
case GLChunk::glVertexAttrib1fv:
case GLChunk::glVertexAttrib1fvARB:
case GLChunk::glVertexAttrib1s:
case GLChunk::glVertexAttrib1sARB:
case GLChunk::glVertexAttrib1sv:
case GLChunk::glVertexAttrib1svARB:
case GLChunk::glVertexAttrib2d:
case GLChunk::glVertexAttrib2dARB:
case GLChunk::glVertexAttrib2dv:
case GLChunk::glVertexAttrib2dvARB:
case GLChunk::glVertexAttrib2f:
case GLChunk::glVertexAttrib2fARB:
case GLChunk::glVertexAttrib2fv:
case GLChunk::glVertexAttrib2fvARB:
case GLChunk::glVertexAttrib2s:
case GLChunk::glVertexAttrib2sARB:
case GLChunk::glVertexAttrib2sv:
case GLChunk::glVertexAttrib2svARB:
case GLChunk::glVertexAttrib3d:
case GLChunk::glVertexAttrib3dARB:
case GLChunk::glVertexAttrib3dv:
case GLChunk::glVertexAttrib3dvARB:
case GLChunk::glVertexAttrib3f:
case GLChunk::glVertexAttrib3fARB:
case GLChunk::glVertexAttrib3fv:
case GLChunk::glVertexAttrib3fvARB:
case GLChunk::glVertexAttrib3s:
case GLChunk::glVertexAttrib3sARB:
case GLChunk::glVertexAttrib3sv:
case GLChunk::glVertexAttrib3svARB:
case GLChunk::glVertexAttrib4bv:
case GLChunk::glVertexAttrib4bvARB:
case GLChunk::glVertexAttrib4d:
case GLChunk::glVertexAttrib4dARB:
case GLChunk::glVertexAttrib4dv:
case GLChunk::glVertexAttrib4dvARB:
case GLChunk::glVertexAttrib4f:
case GLChunk::glVertexAttrib4fARB:
case GLChunk::glVertexAttrib4fv:
case GLChunk::glVertexAttrib4fvARB:
case GLChunk::glVertexAttrib4iv:
case GLChunk::glVertexAttrib4ivARB:
case GLChunk::glVertexAttrib4Nbv:
case GLChunk::glVertexAttrib4NbvARB:
case GLChunk::glVertexAttrib4Niv:
case GLChunk::glVertexAttrib4NivARB:
case GLChunk::glVertexAttrib4Nsv:
case GLChunk::glVertexAttrib4NsvARB:
case GLChunk::glVertexAttrib4Nub:
case GLChunk::glVertexAttrib4Nubv:
case GLChunk::glVertexAttrib4NubvARB:
case GLChunk::glVertexAttrib4Nuiv:
case GLChunk::glVertexAttrib4NuivARB:
case GLChunk::glVertexAttrib4Nusv:
case GLChunk::glVertexAttrib4NusvARB:
case GLChunk::glVertexAttrib4s:
case GLChunk::glVertexAttrib4sARB:
case GLChunk::glVertexAttrib4sv:
case GLChunk::glVertexAttrib4svARB:
case GLChunk::glVertexAttrib4ubv:
case GLChunk::glVertexAttrib4ubvARB:
case GLChunk::glVertexAttrib4uiv:
case GLChunk::glVertexAttrib4uivARB:
case GLChunk::glVertexAttrib4usv:
case GLChunk::glVertexAttrib4usvARB:
case GLChunk::glVertexAttribI1i:
case GLChunk::glVertexAttribI1iEXT:
case GLChunk::glVertexAttribI1iv:
case GLChunk::glVertexAttribI1ivEXT:
case GLChunk::glVertexAttribI1ui:
case GLChunk::glVertexAttribI1uiEXT:
case GLChunk::glVertexAttribI1uiv:
case GLChunk::glVertexAttribI1uivEXT:
case GLChunk::glVertexAttribI2i:
case GLChunk::glVertexAttribI2iEXT:
case GLChunk::glVertexAttribI2iv:
case GLChunk::glVertexAttribI2ivEXT:
case GLChunk::glVertexAttribI2ui:
case GLChunk::glVertexAttribI2uiEXT:
case GLChunk::glVertexAttribI2uiv:
case GLChunk::glVertexAttribI2uivEXT:
case GLChunk::glVertexAttribI3i:
case GLChunk::glVertexAttribI3iEXT:
case GLChunk::glVertexAttribI3iv:
case GLChunk::glVertexAttribI3ivEXT:
case GLChunk::glVertexAttribI3ui:
case GLChunk::glVertexAttribI3uiEXT:
case GLChunk::glVertexAttribI3uiv:
case GLChunk::glVertexAttribI3uivEXT:
case GLChunk::glVertexAttribI4bv:
case GLChunk::glVertexAttribI4bvEXT:
case GLChunk::glVertexAttribI4i:
case GLChunk::glVertexAttribI4iEXT:
case GLChunk::glVertexAttribI4iv:
case GLChunk::glVertexAttribI4ivEXT:
case GLChunk::glVertexAttribI4sv:
case GLChunk::glVertexAttribI4svEXT:
case GLChunk::glVertexAttribI4ubv:
case GLChunk::glVertexAttribI4ubvEXT:
case GLChunk::glVertexAttribI4ui:
case GLChunk::glVertexAttribI4uiEXT:
case GLChunk::glVertexAttribI4uiv:
case GLChunk::glVertexAttribI4uivEXT:
case GLChunk::glVertexAttribI4usv:
case GLChunk::glVertexAttribI4usvEXT:
case GLChunk::glVertexAttribL1d:
case GLChunk::glVertexAttribL1dEXT:
case GLChunk::glVertexAttribL1dv:
case GLChunk::glVertexAttribL1dvEXT:
case GLChunk::glVertexAttribL2d:
case GLChunk::glVertexAttribL2dEXT:
case GLChunk::glVertexAttribL2dv:
case GLChunk::glVertexAttribL2dvEXT:
case GLChunk::glVertexAttribL3d:
case GLChunk::glVertexAttribL3dEXT:
case GLChunk::glVertexAttribL3dv:
case GLChunk::glVertexAttribL3dvEXT:
case GLChunk::glVertexAttribL4d:
case GLChunk::glVertexAttribL4dEXT:
case GLChunk::glVertexAttribL4dv:
case GLChunk::glVertexAttribL4dvEXT:
case GLChunk::glVertexAttribP1ui:
case GLChunk::glVertexAttribP1uiv:
case GLChunk::glVertexAttribP2ui:
case GLChunk::glVertexAttribP2uiv:
case GLChunk::glVertexAttribP3ui:
case GLChunk::glVertexAttribP3uiv:
case GLChunk::glVertexAttribP4ui:
case GLChunk::glVertexAttribP4uiv:
return Serialise_glVertexAttrib(ser, 0, 0, eGL_NONE, 0, 0, Attrib_typemask);
case GLChunk::glLabelObjectEXT:
case GLChunk::glObjectLabelKHR:
case GLChunk::glObjectPtrLabel:
case GLChunk::glObjectPtrLabelKHR:
case GLChunk::glObjectLabel: return Serialise_glObjectLabel(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glDebugMessageInsertARB:
case GLChunk::glDebugMessageInsertKHR:
case GLChunk::glDebugMessageInsert:
return Serialise_glDebugMessageInsert(ser, eGL_NONE, eGL_NONE, 0, eGL_NONE, 0, 0);
case GLChunk::glStringMarkerGREMEDY:
case GLChunk::glInsertEventMarkerEXT: return Serialise_glInsertEventMarkerEXT(ser, 0, 0);
case GLChunk::glPushGroupMarkerEXT:
case GLChunk::glPushDebugGroupKHR:
case GLChunk::glPushDebugGroup: return Serialise_glPushDebugGroup(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glPopGroupMarkerEXT:
case GLChunk::glPopDebugGroupKHR:
case GLChunk::glPopDebugGroup: return Serialise_glPopDebugGroup(ser);
case GLChunk::glDispatchCompute: return Serialise_glDispatchCompute(ser, 0, 0, 0);
case GLChunk::glDispatchComputeGroupSizeARB:
return Serialise_glDispatchComputeGroupSizeARB(ser, 0, 0, 0, 0, 0, 0);
case GLChunk::glDispatchComputeIndirect: return Serialise_glDispatchComputeIndirect(ser, 0);
case GLChunk::glMemoryBarrierEXT:
case GLChunk::glMemoryBarrier: return Serialise_glMemoryBarrier(ser, 0);
case GLChunk::glMemoryBarrierByRegion: return Serialise_glMemoryBarrierByRegion(ser, 0);
case GLChunk::glTextureBarrier: return Serialise_glTextureBarrier(ser);
case GLChunk::glDrawTransformFeedback:
return Serialise_glDrawTransformFeedback(ser, eGL_NONE, 0);
case GLChunk::glDrawTransformFeedbackInstanced:
return Serialise_glDrawTransformFeedbackInstanced(ser, eGL_NONE, 0, 0);
case GLChunk::glDrawTransformFeedbackStream:
return Serialise_glDrawTransformFeedbackStream(ser, eGL_NONE, 0, 0);
case GLChunk::glDrawTransformFeedbackStreamInstanced:
return Serialise_glDrawTransformFeedbackStreamInstanced(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glDrawArrays: return Serialise_glDrawArrays(ser, eGL_NONE, 0, 0);
case GLChunk::glDrawArraysIndirect: return Serialise_glDrawArraysIndirect(ser, eGL_NONE, 0);
case GLChunk::glDrawArraysInstancedARB:
case GLChunk::glDrawArraysInstancedEXT:
case GLChunk::glDrawArraysInstanced:
return Serialise_glDrawArraysInstanced(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glDrawArraysInstancedBaseInstanceEXT:
case GLChunk::glDrawArraysInstancedBaseInstance:
return Serialise_glDrawArraysInstancedBaseInstance(ser, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glDrawElements: return Serialise_glDrawElements(ser, eGL_NONE, 0, eGL_NONE, 0);
case GLChunk::glDrawElementsIndirect:
return Serialise_glDrawElementsIndirect(ser, eGL_NONE, eGL_NONE, 0);
case GLChunk::glDrawRangeElementsEXT:
case GLChunk::glDrawRangeElements:
return Serialise_glDrawRangeElements(ser, eGL_NONE, 0, 0, 0, eGL_NONE, 0);
case GLChunk::glDrawRangeElementsBaseVertexEXT:
case GLChunk::glDrawRangeElementsBaseVertexOES:
case GLChunk::glDrawRangeElementsBaseVertex:
return Serialise_glDrawRangeElementsBaseVertex(ser, eGL_NONE, 0, 0, 0, eGL_NONE, 0, 0);
case GLChunk::glDrawElementsBaseVertexEXT:
case GLChunk::glDrawElementsBaseVertexOES:
case GLChunk::glDrawElementsBaseVertex:
return Serialise_glDrawElementsBaseVertex(ser, eGL_NONE, 0, eGL_NONE, 0, 0);
case GLChunk::glDrawElementsInstancedARB:
case GLChunk::glDrawElementsInstancedEXT:
case GLChunk::glDrawElementsInstanced:
return Serialise_glDrawElementsInstanced(ser, eGL_NONE, 0, eGL_NONE, 0, 0);
case GLChunk::glDrawElementsInstancedBaseInstanceEXT:
case GLChunk::glDrawElementsInstancedBaseInstance:
return Serialise_glDrawElementsInstancedBaseInstance(ser, eGL_NONE, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glDrawElementsInstancedBaseVertexEXT:
case GLChunk::glDrawElementsInstancedBaseVertexOES:
case GLChunk::glDrawElementsInstancedBaseVertex:
return Serialise_glDrawElementsInstancedBaseVertex(ser, eGL_NONE, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glDrawElementsInstancedBaseVertexBaseInstanceEXT:
case GLChunk::glDrawElementsInstancedBaseVertexBaseInstance:
return Serialise_glDrawElementsInstancedBaseVertexBaseInstance(ser, eGL_NONE, 0, eGL_NONE, 0,
0, 0, 0);
case GLChunk::glMultiDrawArraysEXT:
case GLChunk::glMultiDrawArrays: return Serialise_glMultiDrawArrays(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glMultiDrawElements:
return Serialise_glMultiDrawElements(ser, eGL_NONE, 0, eGL_NONE, 0, 0);
case GLChunk::glMultiDrawElementsBaseVertexEXT:
case GLChunk::glMultiDrawElementsBaseVertexOES:
case GLChunk::glMultiDrawElementsBaseVertex:
return Serialise_glMultiDrawElementsBaseVertex(ser, eGL_NONE, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glMultiDrawArraysIndirect:
return Serialise_glMultiDrawArraysIndirect(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glMultiDrawElementsIndirect:
return Serialise_glMultiDrawElementsIndirect(ser, eGL_NONE, eGL_NONE, 0, 0, 0);
case GLChunk::glMultiDrawArraysIndirectCountARB:
case GLChunk::glMultiDrawArraysIndirectCount:
return Serialise_glMultiDrawArraysIndirectCount(ser, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glMultiDrawElementsIndirectCountARB:
case GLChunk::glMultiDrawElementsIndirectCount:
return Serialise_glMultiDrawElementsIndirectCount(ser, eGL_NONE, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glClearBufferfv:
case GLChunk::glClearNamedFramebufferfv:
return Serialise_glClearNamedFramebufferfv(ser, 0, eGL_NONE, 0, 0);
case GLChunk::glClearBufferiv:
case GLChunk::glClearNamedFramebufferiv:
return Serialise_glClearNamedFramebufferiv(ser, 0, eGL_NONE, 0, 0);
case GLChunk::glClearBufferuiv:
case GLChunk::glClearNamedFramebufferuiv:
return Serialise_glClearNamedFramebufferuiv(ser, 0, eGL_NONE, 0, 0);
case GLChunk::glClearBufferfi:
case GLChunk::glClearNamedFramebufferfi:
return Serialise_glClearNamedFramebufferfi(ser, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glClearBufferData:
case GLChunk::glClearNamedBufferData:
case GLChunk::glClearNamedBufferDataEXT:
return Serialise_glClearNamedBufferDataEXT(ser, 0, eGL_NONE, eGL_NONE, eGL_NONE, 0);
case GLChunk::glClearBufferSubData:
case GLChunk::glClearNamedBufferSubData:
case GLChunk::glClearNamedBufferSubDataEXT:
return Serialise_glClearNamedBufferSubDataEXT(ser, 0, eGL_NONE, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glClear: return Serialise_glClear(ser, 0);
case GLChunk::glClearTexImage:
return Serialise_glClearTexImage(ser, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glClearTexSubImage:
return Serialise_glClearTexSubImage(ser, 0, 0, 0, 0, 0, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glGenFramebuffersEXT:
case GLChunk::glGenFramebuffers: return Serialise_glGenFramebuffers(ser, 0, 0);
case GLChunk::glCreateFramebuffers: return Serialise_glCreateFramebuffers(ser, 0, 0);
case GLChunk::glFramebufferTexture:
case GLChunk::glFramebufferTextureOES:
case GLChunk::glFramebufferTextureARB:
case GLChunk::glFramebufferTextureEXT:
case GLChunk::glNamedFramebufferTexture:
case GLChunk::glNamedFramebufferTextureEXT:
return Serialise_glNamedFramebufferTextureEXT(ser, 0, eGL_NONE, 0, 0);
case GLChunk::glFramebufferTexture1D:
case GLChunk::glFramebufferTexture1DEXT:
case GLChunk::glNamedFramebufferTexture1DEXT:
return Serialise_glNamedFramebufferTexture1DEXT(ser, 0, eGL_NONE, eGL_NONE, 0, 0);
case GLChunk::glFramebufferTexture2D:
case GLChunk::glFramebufferTexture2DEXT:
case GLChunk::glNamedFramebufferTexture2DEXT:
return Serialise_glNamedFramebufferTexture2DEXT(ser, 0, eGL_NONE, eGL_NONE, 0, 0);
case GLChunk::glFramebufferTexture2DMultisampleEXT:
return Serialise_glFramebufferTexture2DMultisampleEXT(ser, 0, eGL_NONE, eGL_NONE, eGL_NONE, 0,
0, 0);
case GLChunk::glFramebufferTexture3D:
case GLChunk::glFramebufferTexture3DEXT:
case GLChunk::glFramebufferTexture3DOES:
case GLChunk::glNamedFramebufferTexture3DEXT:
return Serialise_glNamedFramebufferTexture3DEXT(ser, 0, eGL_NONE, eGL_NONE, 0, 0, 0);
case GLChunk::glFramebufferRenderbuffer:
case GLChunk::glFramebufferRenderbufferEXT:
case GLChunk::glNamedFramebufferRenderbuffer:
case GLChunk::glNamedFramebufferRenderbufferEXT:
return Serialise_glNamedFramebufferRenderbufferEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glFramebufferTextureLayer:
case GLChunk::glFramebufferTextureLayerARB:
case GLChunk::glFramebufferTextureLayerEXT:
case GLChunk::glNamedFramebufferTextureLayer:
case GLChunk::glNamedFramebufferTextureLayerEXT:
return Serialise_glNamedFramebufferTextureLayerEXT(ser, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glFramebufferTextureMultiviewOVR:
return Serialise_glFramebufferTextureMultiviewOVR(ser, eGL_NONE, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glFramebufferTextureMultisampleMultiviewOVR:
return Serialise_glFramebufferTextureMultisampleMultiviewOVR(ser, eGL_NONE, eGL_NONE, 0, 0, 0,
0, 0);
case GLChunk::glTextureFoveationParametersQCOM:
return Serialise_glTextureFoveationParametersQCOM(ser, eGL_NONE, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f);
case GLChunk::glFramebufferParameteri:
case GLChunk::glNamedFramebufferParameteri:
case GLChunk::glNamedFramebufferParameteriEXT:
return Serialise_glNamedFramebufferParameteriEXT(ser, 0, eGL_NONE, 0);
case GLChunk::glReadBuffer:
case GLChunk::glNamedFramebufferReadBuffer:
case GLChunk::glFramebufferReadBufferEXT:
return Serialise_glFramebufferReadBufferEXT(ser, 0, eGL_NONE);
case GLChunk::glBindFramebufferEXT:
case GLChunk::glBindFramebuffer: return Serialise_glBindFramebuffer(ser, eGL_NONE, 0);
case GLChunk::glDiscardFramebufferEXT:
case GLChunk::glInvalidateFramebuffer:
case GLChunk::glInvalidateNamedFramebufferData:
return Serialise_glInvalidateNamedFramebufferData(ser, 0, 0, 0);
case GLChunk::glDrawBuffer:
case GLChunk::glNamedFramebufferDrawBuffer:
case GLChunk::glFramebufferDrawBufferEXT:
return Serialise_glFramebufferDrawBufferEXT(ser, 0, eGL_NONE);
case GLChunk::glDrawBuffers:
case GLChunk::glDrawBuffersARB:
case GLChunk::glDrawBuffersEXT:
case GLChunk::glNamedFramebufferDrawBuffers:
case GLChunk::glFramebufferDrawBuffersEXT:
return Serialise_glFramebufferDrawBuffersEXT(ser, 0, 0, 0);
case GLChunk::glBlitFramebuffer:
case GLChunk::glBlitFramebufferEXT:
case GLChunk::glBlitNamedFramebuffer:
return Serialise_glBlitNamedFramebuffer(ser, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, eGL_NONE);
case GLChunk::glGenRenderbuffersEXT:
case GLChunk::glGenRenderbuffers: return Serialise_glGenRenderbuffers(ser, 0, 0);
case GLChunk::glCreateRenderbuffers: return Serialise_glCreateRenderbuffers(ser, 0, 0);
case GLChunk::glRenderbufferStorage:
case GLChunk::glRenderbufferStorageEXT:
case GLChunk::glNamedRenderbufferStorage:
case GLChunk::glNamedRenderbufferStorageEXT:
return Serialise_glNamedRenderbufferStorageEXT(ser, 0, eGL_NONE, 0, 0);
case GLChunk::glRenderbufferStorageMultisample:
case GLChunk::glNamedRenderbufferStorageMultisample:
case GLChunk::glNamedRenderbufferStorageMultisampleEXT:
return Serialise_glNamedRenderbufferStorageMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0);
// needs to be separate from glRenderbufferStorageMultisample due to driver issues
case GLChunk::glRenderbufferStorageMultisampleEXT:
return Serialise_glRenderbufferStorageMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0);
case GLChunk::wglDXRegisterObjectNV:
return Serialise_wglDXRegisterObjectNV(ser, GLResource(MakeNullResource), eGL_NONE, 0);
case GLChunk::wglDXLockObjectsNV:
return Serialise_wglDXLockObjectsNV(ser, GLResource(MakeNullResource));
case GLChunk::glFenceSync: return Serialise_glFenceSync(ser, 0, eGL_NONE, 0);
case GLChunk::glClientWaitSync: return Serialise_glClientWaitSync(ser, 0, 0, 0);
case GLChunk::glWaitSync: return Serialise_glWaitSync(ser, 0, 0, 0);
case GLChunk::glGenQueriesARB:
case GLChunk::glGenQueriesEXT:
case GLChunk::glGenQueries: return Serialise_glGenQueries(ser, 0, 0);
case GLChunk::glCreateQueries: return Serialise_glCreateQueries(ser, eGL_NONE, 0, 0);
case GLChunk::glBeginQueryARB:
case GLChunk::glBeginQueryEXT:
case GLChunk::glBeginQuery: return Serialise_glBeginQuery(ser, eGL_NONE, 0);
case GLChunk::glBeginQueryIndexed: return Serialise_glBeginQueryIndexed(ser, eGL_NONE, 0, 0);
case GLChunk::glEndQueryARB:
case GLChunk::glEndQueryEXT:
case GLChunk::glEndQuery: return Serialise_glEndQuery(ser, eGL_NONE);
case GLChunk::glEndQueryIndexed: return Serialise_glEndQueryIndexed(ser, eGL_NONE, 0);
case GLChunk::glBeginConditionalRender:
return Serialise_glBeginConditionalRender(ser, 0, eGL_NONE);
case GLChunk::glEndConditionalRender: return Serialise_glEndConditionalRender(ser);
case GLChunk::glQueryCounterEXT:
case GLChunk::glQueryCounter: return Serialise_glQueryCounter(ser, 0, eGL_NONE);
case GLChunk::glGenSamplers: return Serialise_glGenSamplers(ser, 0, 0);
case GLChunk::glCreateSamplers: return Serialise_glCreateSamplers(ser, 0, 0);
case GLChunk::glBindSampler: return Serialise_glBindSampler(ser, 0, 0);
case GLChunk::glBindSamplers: return Serialise_glBindSamplers(ser, 0, 0, 0);
case GLChunk::glSamplerParameteri: return Serialise_glSamplerParameteri(ser, 0, eGL_NONE, 0);
case GLChunk::glSamplerParameterf: return Serialise_glSamplerParameterf(ser, 0, eGL_NONE, 0);
case GLChunk::glSamplerParameteriv: return Serialise_glSamplerParameteriv(ser, 0, eGL_NONE, 0);
case GLChunk::glSamplerParameterfv: return Serialise_glSamplerParameterfv(ser, 0, eGL_NONE, 0);
case GLChunk::glSamplerParameterIivEXT:
case GLChunk::glSamplerParameterIivOES:
case GLChunk::glSamplerParameterIiv:
return Serialise_glSamplerParameterIiv(ser, 0, eGL_NONE, 0);
case GLChunk::glSamplerParameterIuivEXT:
case GLChunk::glSamplerParameterIuivOES:
case GLChunk::glSamplerParameterIuiv:
return Serialise_glSamplerParameterIuiv(ser, 0, eGL_NONE, 0);
case GLChunk::glCreateShader: return Serialise_glCreateShader(ser, eGL_NONE, 0);
case GLChunk::glShaderSource: return Serialise_glShaderSource(ser, 0, 0, 0, 0);
case GLChunk::glCompileShader: return Serialise_glCompileShader(ser, 0);
case GLChunk::glAttachShader: return Serialise_glAttachShader(ser, 0, 0);
case GLChunk::glDetachShader: return Serialise_glDetachShader(ser, 0, 0);
case GLChunk::glCreateShaderProgramvEXT:
case GLChunk::glCreateShaderProgramv:
return Serialise_glCreateShaderProgramv(ser, eGL_NONE, 0, 0, 0);
case GLChunk::glCreateProgram: return Serialise_glCreateProgram(ser, 0);
case GLChunk::glLinkProgram: return Serialise_glLinkProgram(ser, 0);
case GLChunk::glUniformBlockBinding: return Serialise_glUniformBlockBinding(ser, 0, 0, 0);
case GLChunk::glShaderStorageBlockBinding:
return Serialise_glShaderStorageBlockBinding(ser, 0, 0, 0);
case GLChunk::glBindAttribLocation: return Serialise_glBindAttribLocation(ser, 0, 0, 0);
case GLChunk::glBindFragDataLocationEXT:
case GLChunk::glBindFragDataLocation: return Serialise_glBindFragDataLocation(ser, 0, 0, 0);
case GLChunk::glUniformSubroutinesuiv:
return Serialise_glUniformSubroutinesuiv(ser, eGL_NONE, 0, 0);
case GLChunk::glBindFragDataLocationIndexed:
return Serialise_glBindFragDataLocationIndexed(ser, 0, 0, 0, 0);
case GLChunk::glTransformFeedbackVaryingsEXT:
case GLChunk::glTransformFeedbackVaryings:
return Serialise_glTransformFeedbackVaryings(ser, 0, 0, 0, eGL_NONE);
case GLChunk::glProgramParameteriARB:
case GLChunk::glProgramParameteriEXT:
case GLChunk::glProgramParameteri: return Serialise_glProgramParameteri(ser, 0, eGL_NONE, 0);
case GLChunk::glUseProgram: return Serialise_glUseProgram(ser, 0);
case GLChunk::glUseProgramStagesEXT:
case GLChunk::glUseProgramStages: return Serialise_glUseProgramStages(ser, 0, 0, 0);
case GLChunk::glGenProgramPipelinesEXT:
case GLChunk::glGenProgramPipelines: return Serialise_glGenProgramPipelines(ser, 0, 0);
case GLChunk::glCreateProgramPipelines: return Serialise_glCreateProgramPipelines(ser, 0, 0);
case GLChunk::glBindProgramPipelineEXT:
case GLChunk::glBindProgramPipeline: return Serialise_glBindProgramPipeline(ser, 0);
case GLChunk::glCompileShaderIncludeARB:
return Serialise_glCompileShaderIncludeARB(ser, 0, 0, 0, 0);
case GLChunk::glNamedStringARB: return Serialise_glNamedStringARB(ser, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glDeleteNamedStringARB: return Serialise_glDeleteNamedStringARB(ser, 0, 0);
case GLChunk::glBlendFunc: return Serialise_glBlendFunc(ser, eGL_NONE, eGL_NONE);
case GLChunk::glBlendFunciARB:
case GLChunk::glBlendFunciEXT:
case GLChunk::glBlendFunciOES:
case GLChunk::glBlendFunci: return Serialise_glBlendFunci(ser, 0, eGL_NONE, eGL_NONE);
case GLChunk::glBlendColorEXT:
case GLChunk::glBlendColor: return Serialise_glBlendColor(ser, 0, 0, 0, 0);
case GLChunk::glBlendFuncSeparateARB:
case GLChunk::glBlendFuncSeparate:
return Serialise_glBlendFuncSeparate(ser, eGL_NONE, eGL_NONE, eGL_NONE, eGL_NONE);
case GLChunk::glBlendFuncSeparateiARB:
case GLChunk::glBlendFuncSeparateiEXT:
case GLChunk::glBlendFuncSeparateiOES:
case GLChunk::glBlendFuncSeparatei:
return Serialise_glBlendFuncSeparatei(ser, 0, eGL_NONE, eGL_NONE, eGL_NONE, eGL_NONE);
case GLChunk::glBlendEquationEXT:
case GLChunk::glBlendEquationARB:
case GLChunk::glBlendEquation: return Serialise_glBlendEquation(ser, eGL_NONE);
case GLChunk::glBlendEquationiARB:
case GLChunk::glBlendEquationiEXT:
case GLChunk::glBlendEquationiOES:
case GLChunk::glBlendEquationi: return Serialise_glBlendEquationi(ser, 0, eGL_NONE);
case GLChunk::glBlendEquationSeparateARB:
case GLChunk::glBlendEquationSeparateEXT:
case GLChunk::glBlendEquationSeparate:
return Serialise_glBlendEquationSeparate(ser, eGL_NONE, eGL_NONE);
case GLChunk::glBlendEquationSeparateiARB:
case GLChunk::glBlendEquationSeparateiEXT:
case GLChunk::glBlendEquationSeparateiOES:
case GLChunk::glBlendEquationSeparatei:
return Serialise_glBlendEquationSeparatei(ser, 0, eGL_NONE, eGL_NONE);
case GLChunk::glBlendBarrier:
case GLChunk::glBlendBarrierKHR: return Serialise_glBlendBarrierKHR(ser);
case GLChunk::glLogicOp: return Serialise_glLogicOp(ser, eGL_NONE);
case GLChunk::glStencilFunc: return Serialise_glStencilFunc(ser, eGL_NONE, 0, 0);
case GLChunk::glStencilFuncSeparate:
return Serialise_glStencilFuncSeparate(ser, eGL_NONE, eGL_NONE, 0, 0);
case GLChunk::glStencilMask: return Serialise_glStencilMask(ser, 0);
case GLChunk::glStencilMaskSeparate: return Serialise_glStencilMaskSeparate(ser, eGL_NONE, 0);
case GLChunk::glStencilOp: return Serialise_glStencilOp(ser, eGL_NONE, eGL_NONE, eGL_NONE);
case GLChunk::glStencilOpSeparate:
return Serialise_glStencilOpSeparate(ser, eGL_NONE, eGL_NONE, eGL_NONE, eGL_NONE);
case GLChunk::glClearColor: return Serialise_glClearColor(ser, 0, 0, 0, 0);
case GLChunk::glClearStencil: return Serialise_glClearStencil(ser, 0);
case GLChunk::glClearDepthf:
case GLChunk::glClearDepth: return Serialise_glClearDepth(ser, 0);
case GLChunk::glDepthFunc: return Serialise_glDepthFunc(ser, eGL_NONE);
case GLChunk::glDepthMask: return Serialise_glDepthMask(ser, 0);
case GLChunk::glDepthRange: return Serialise_glDepthRange(ser, 0, 0);
case GLChunk::glDepthRangef: return Serialise_glDepthRangef(ser, 0, 0);
case GLChunk::glDepthRangeIndexedfNV:
case GLChunk::glDepthRangeIndexedfOES:
case GLChunk::glDepthRangeIndexed: return Serialise_glDepthRangeIndexed(ser, 0, 0, 0);
case GLChunk::glDepthRangeArrayfvNV:
case GLChunk::glDepthRangeArrayfvOES:
case GLChunk::glDepthRangeArrayv: return Serialise_glDepthRangeArrayv(ser, 0, 0, 0);
case GLChunk::glDepthBoundsEXT: return Serialise_glDepthBoundsEXT(ser, 0, 0);
case GLChunk::glClipControl: return Serialise_glClipControl(ser, eGL_NONE, eGL_NONE);
case GLChunk::glProvokingVertexEXT:
case GLChunk::glProvokingVertex: return Serialise_glProvokingVertex(ser, eGL_NONE);
case GLChunk::glPrimitiveRestartIndex: return Serialise_glPrimitiveRestartIndex(ser, 0);
case GLChunk::glDisable: return Serialise_glDisable(ser, eGL_NONE);
case GLChunk::glEnable: return Serialise_glEnable(ser, eGL_NONE);
case GLChunk::glDisableiEXT:
case GLChunk::glDisableIndexedEXT:
case GLChunk::glDisableiNV:
case GLChunk::glDisableiOES:
case GLChunk::glDisablei: return Serialise_glDisablei(ser, eGL_NONE, 0);
case GLChunk::glEnableiEXT:
case GLChunk::glEnableIndexedEXT:
case GLChunk::glEnableiNV:
case GLChunk::glEnableiOES:
case GLChunk::glEnablei: return Serialise_glEnablei(ser, eGL_NONE, 0);
case GLChunk::glFrontFace: return Serialise_glFrontFace(ser, eGL_NONE);
case GLChunk::glCullFace: return Serialise_glCullFace(ser, eGL_NONE);
case GLChunk::glHint: return Serialise_glHint(ser, eGL_NONE, eGL_NONE);
case GLChunk::glColorMask: return Serialise_glColorMask(ser, 0, 0, 0, 0);
case GLChunk::glColorMaskiEXT:
case GLChunk::glColorMaskIndexedEXT:
case GLChunk::glColorMaskiOES:
case GLChunk::glColorMaski: return Serialise_glColorMaski(ser, 0, 0, 0, 0, 0);
case GLChunk::glSampleMaski: return Serialise_glSampleMaski(ser, 0, 0);
case GLChunk::glSampleCoverageARB:
case GLChunk::glSampleCoverage: return Serialise_glSampleCoverage(ser, 0, 0);
case GLChunk::glMinSampleShadingARB:
case GLChunk::glMinSampleShadingOES:
case GLChunk::glMinSampleShading: return Serialise_glMinSampleShading(ser, 0);
case GLChunk::glRasterSamplesEXT: return Serialise_glRasterSamplesEXT(ser, 0, 0);
case GLChunk::glPatchParameteri: return Serialise_glPatchParameteri(ser, eGL_NONE, 0);
case GLChunk::glPatchParameterfv: return Serialise_glPatchParameterfv(ser, eGL_NONE, 0);
case GLChunk::glLineWidth: return Serialise_glLineWidth(ser, 0);
case GLChunk::glPointSize: return Serialise_glPointSize(ser, 0);
case GLChunk::glPatchParameteriEXT:
case GLChunk::glPatchParameteriOES:
case GLChunk::glPointParameteri: return Serialise_glPointParameteri(ser, eGL_NONE, 0);
case GLChunk::glPointParameteriv: return Serialise_glPointParameteriv(ser, eGL_NONE, 0);
case GLChunk::glPointParameterfARB:
case GLChunk::glPointParameterfEXT:
case GLChunk::glPointParameterf: return Serialise_glPointParameterf(ser, eGL_NONE, 0);
case GLChunk::glPointParameterfvARB:
case GLChunk::glPointParameterfvEXT:
case GLChunk::glPointParameterfv: return Serialise_glPointParameterfv(ser, eGL_NONE, 0);
case GLChunk::glViewport: return Serialise_glViewport(ser, 0, 0, 0, 0);
case GLChunk::glViewportArrayvNV:
case GLChunk::glViewportArrayvOES:
case GLChunk::glViewportIndexedf:
case GLChunk::glViewportIndexedfNV:
case GLChunk::glViewportIndexedfOES:
case GLChunk::glViewportIndexedfv:
case GLChunk::glViewportIndexedfvNV:
case GLChunk::glViewportIndexedfvOES:
case GLChunk::glViewportArrayv: return Serialise_glViewportArrayv(ser, 0, 0, 0);
case GLChunk::glScissor: return Serialise_glScissor(ser, 0, 0, 0, 0);
case GLChunk::glScissorArrayvNV:
case GLChunk::glScissorArrayvOES:
case GLChunk::glScissorIndexed:
case GLChunk::glScissorIndexedNV:
case GLChunk::glScissorIndexedOES:
case GLChunk::glScissorIndexedv:
case GLChunk::glScissorIndexedvNV:
case GLChunk::glScissorIndexedvOES:
case GLChunk::glScissorArrayv: return Serialise_glScissorArrayv(ser, 0, 0, 0);
case GLChunk::glPolygonMode: return Serialise_glPolygonMode(ser, eGL_NONE, eGL_NONE);
case GLChunk::glPolygonOffset: return Serialise_glPolygonOffset(ser, 0, 0);
case GLChunk::glPolygonOffsetClampEXT:
case GLChunk::glPolygonOffsetClamp: return Serialise_glPolygonOffsetClamp(ser, 0, 0, 0);
case GLChunk::glPrimitiveBoundingBoxEXT:
case GLChunk::glPrimitiveBoundingBoxOES:
case GLChunk::glPrimitiveBoundingBoxARB:
case GLChunk::glPrimitiveBoundingBox:
return Serialise_glPrimitiveBoundingBox(ser, 0, 0, 0, 0, 0, 0, 0, 0);
case GLChunk::glGenTextures: return Serialise_glGenTextures(ser, 0, 0);
case GLChunk::glCreateTextures: return Serialise_glCreateTextures(ser, eGL_NONE, 0, 0);
case GLChunk::glBindTexture: return Serialise_glBindTexture(ser, eGL_NONE, 0);
case GLChunk::glBindTextures: return Serialise_glBindTextures(ser, 0, 0, 0);
case GLChunk::glBindMultiTextureEXT:
return Serialise_glBindMultiTextureEXT(ser, eGL_NONE, eGL_NONE, 0);
case GLChunk::glBindTextureUnit: return Serialise_glBindTextureUnit(ser, 0, 0);
case GLChunk::glBindImageTextureEXT:
case GLChunk::glBindImageTexture:
return Serialise_glBindImageTexture(ser, 0, 0, 0, 0, 0, eGL_NONE, eGL_NONE);
case GLChunk::glBindImageTextures: return Serialise_glBindImageTextures(ser, 0, 0, 0);
case GLChunk::glTextureViewEXT:
case GLChunk::glTextureViewOES:
case GLChunk::glTextureView:
return Serialise_glTextureView(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glGenerateMipmap:
case GLChunk::glGenerateMipmapEXT:
case GLChunk::glGenerateMultiTexMipmapEXT:
case GLChunk::glGenerateTextureMipmap:
case GLChunk::glGenerateTextureMipmapEXT:
return Serialise_glGenerateTextureMipmapEXT(ser, 0, eGL_NONE);
case GLChunk::glCopyImageSubDataEXT:
case GLChunk::glCopyImageSubDataOES:
case GLChunk::glCopyImageSubData:
return Serialise_glCopyImageSubData(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, eGL_NONE, 0, 0, 0, 0, 0,
0, 0);
case GLChunk::glCopyMultiTexSubImage1DEXT:
case GLChunk::glCopyTexSubImage1D:
case GLChunk::glCopyTextureSubImage1D:
case GLChunk::glCopyTextureSubImage1DEXT:
return Serialise_glCopyTextureSubImage1DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0);
case GLChunk::glCopyTexSubImage2D:
case GLChunk::glCopyTextureSubImage2D:
case GLChunk::glCopyMultiTexSubImage2DEXT:
case GLChunk::glCopyTextureSubImage2DEXT:
return Serialise_glCopyTextureSubImage2DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, 0, 0);
case GLChunk::glCopyMultiTexSubImage3DEXT:
case GLChunk::glCopyTexSubImage3D:
case GLChunk::glCopyTexSubImage3DOES:
case GLChunk::glCopyTextureSubImage3D:
case GLChunk::glCopyTextureSubImage3DEXT:
return Serialise_glCopyTextureSubImage3DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, 0, 0, 0);
case GLChunk::glMultiTexParameteriEXT:
case GLChunk::glTexParameteri:
case GLChunk::glTextureParameteri:
case GLChunk::glTextureParameteriEXT:
return Serialise_glTextureParameteriEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexParameterivEXT:
case GLChunk::glTexParameteriv:
case GLChunk::glTextureParameteriv:
case GLChunk::glTextureParameterivEXT:
return Serialise_glTextureParameterivEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexParameterIivEXT:
case GLChunk::glTexParameterIiv:
case GLChunk::glTexParameterIivEXT:
case GLChunk::glTexParameterIivOES:
case GLChunk::glTextureParameterIiv:
case GLChunk::glTextureParameterIivEXT:
return Serialise_glTextureParameterIivEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexParameterIuivEXT:
case GLChunk::glTexParameterIuiv:
case GLChunk::glTexParameterIuivEXT:
case GLChunk::glTexParameterIuivOES:
case GLChunk::glTextureParameterIuiv:
case GLChunk::glTextureParameterIuivEXT:
return Serialise_glTextureParameterIuivEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexParameterfEXT:
case GLChunk::glTexParameterf:
case GLChunk::glTextureParameterf:
case GLChunk::glTextureParameterfEXT:
return Serialise_glTextureParameterfEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexParameterfvEXT:
case GLChunk::glTexParameterfv:
case GLChunk::glTextureParameterfv:
case GLChunk::glTextureParameterfvEXT:
return Serialise_glTextureParameterfvEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glPixelStoref:
case GLChunk::glPixelStorei: return Serialise_glPixelStorei(ser, eGL_NONE, 0);
case GLChunk::glActiveTextureARB:
case GLChunk::glActiveTexture: return Serialise_glActiveTexture(ser, eGL_NONE);
case GLChunk::glMultiTexImage1DEXT:
case GLChunk::glTexImage1D:
case GLChunk::glTextureImage1DEXT:
return Serialise_glTextureImage1DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexImage2DEXT:
case GLChunk::glTexImage2D:
case GLChunk::glTextureImage2DEXT:
return Serialise_glTextureImage2DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexImage3DEXT:
case GLChunk::glTexImage3D:
case GLChunk::glTexImage3DEXT:
case GLChunk::glTexImage3DOES:
case GLChunk::glTextureImage3DEXT:
return Serialise_glTextureImage3DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glCompressedMultiTexImage1DEXT:
case GLChunk::glCompressedTexImage1D:
case GLChunk::glCompressedTexImage1DARB:
case GLChunk::glCompressedTextureImage1DEXT:
return Serialise_glCompressedTextureImage1DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glCompressedMultiTexImage2DEXT:
case GLChunk::glCompressedTexImage2D:
case GLChunk::glCompressedTexImage2DARB:
case GLChunk::glCompressedTextureImage2DEXT:
return Serialise_glCompressedTextureImage2DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0, 0);
case GLChunk::glCompressedMultiTexImage3DEXT:
case GLChunk::glCompressedTexImage3D:
case GLChunk::glCompressedTexImage3DARB:
case GLChunk::glCompressedTexImage3DOES:
case GLChunk::glCompressedTextureImage3DEXT:
return Serialise_glCompressedTextureImage3DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0, 0, 0);
case GLChunk::glCopyTexImage1D:
case GLChunk::glCopyMultiTexImage1DEXT:
case GLChunk::glCopyTextureImage1DEXT:
return Serialise_glCopyTextureImage1DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glCopyTexImage2D:
case GLChunk::glCopyMultiTexImage2DEXT:
case GLChunk::glCopyTextureImage2DEXT:
return Serialise_glCopyTextureImage2DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0, 0);
case GLChunk::glTexStorage1D:
case GLChunk::glTexStorage1DEXT:
case GLChunk::glTextureStorage1D:
case GLChunk::glTextureStorage1DEXT:
return Serialise_glTextureStorage1DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0);
case GLChunk::glTexStorage2D:
case GLChunk::glTexStorage2DEXT:
case GLChunk::glTextureStorage2D:
case GLChunk::glTextureStorage2DEXT:
return Serialise_glTextureStorage2DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0);
case GLChunk::glTexStorage3D:
case GLChunk::glTexStorage3DEXT:
case GLChunk::glTextureStorage3D:
case GLChunk::glTextureStorage3DEXT:
return Serialise_glTextureStorage3DEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glTexImage2DMultisample:
// technically this isn't equivalent to storage, but we treat it as such because there's no DSA
// variant of this teximage
case GLChunk::glTexStorage2DMultisample:
case GLChunk::glTextureStorage2DMultisample:
case GLChunk::glTextureStorage2DMultisampleEXT:
return Serialise_glTextureStorage2DMultisampleEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glTexImage3DMultisample:
// technically this isn't equivalent to storage, but we treat it as such because there's no DSA
// variant of this teximage
case GLChunk::glTexStorage3DMultisample:
case GLChunk::glTexStorage3DMultisampleOES:
case GLChunk::glTextureStorage3DMultisample:
case GLChunk::glTextureStorage3DMultisampleEXT:
return Serialise_glTextureStorage3DMultisampleEXT(ser, 0, eGL_NONE, 0, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glMultiTexSubImage1DEXT:
case GLChunk::glTexSubImage1D:
case GLChunk::glTextureSubImage1D:
case GLChunk::glTextureSubImage1DEXT:
return Serialise_glTextureSubImage1DEXT(ser, 0, eGL_NONE, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexSubImage2DEXT:
case GLChunk::glTexSubImage2D:
case GLChunk::glTextureSubImage2D:
case GLChunk::glTextureSubImage2DEXT:
return Serialise_glTextureSubImage2DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glMultiTexSubImage3DEXT:
case GLChunk::glTexSubImage3D:
case GLChunk::glTexSubImage3DOES:
case GLChunk::glTextureSubImage3D:
case GLChunk::glTextureSubImage3DEXT:
return Serialise_glTextureSubImage3DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, 0, 0, eGL_NONE,
eGL_NONE, 0);
case GLChunk::glCompressedMultiTexSubImage1DEXT:
case GLChunk::glCompressedTexSubImage1D:
case GLChunk::glCompressedTexSubImage1DARB:
case GLChunk::glCompressedTextureSubImage1D:
case GLChunk::glCompressedTextureSubImage1DEXT:
return Serialise_glCompressedTextureSubImage1DEXT(ser, 0, eGL_NONE, 0, 0, 0, eGL_NONE, 0, 0);
case GLChunk::glCompressedMultiTexSubImage2DEXT:
case GLChunk::glCompressedTexSubImage2D:
case GLChunk::glCompressedTexSubImage2DARB:
case GLChunk::glCompressedTextureSubImage2D:
case GLChunk::glCompressedTextureSubImage2DEXT:
return Serialise_glCompressedTextureSubImage2DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, eGL_NONE,
0, 0);
case GLChunk::glCompressedMultiTexSubImage3DEXT:
case GLChunk::glCompressedTexSubImage3D:
case GLChunk::glCompressedTexSubImage3DARB:
case GLChunk::glCompressedTexSubImage3DOES:
case GLChunk::glCompressedTextureSubImage3D:
case GLChunk::glCompressedTextureSubImage3DEXT:
return Serialise_glCompressedTextureSubImage3DEXT(ser, 0, eGL_NONE, 0, 0, 0, 0, 0, 0, 0,
eGL_NONE, 0, 0);
case GLChunk::glTexBufferRange:
case GLChunk::glTexBufferRangeEXT:
case GLChunk::glTexBufferRangeOES:
case GLChunk::glTextureBufferRange:
case GLChunk::glTextureBufferRangeEXT:
return Serialise_glTextureBufferRangeEXT(ser, 0, eGL_NONE, eGL_NONE, 0, 0, 0);
case GLChunk::glMultiTexBufferEXT:
case GLChunk::glTexBuffer:
case GLChunk::glTexBufferARB:
case GLChunk::glTexBufferEXT:
case GLChunk::glTexBufferOES:
case GLChunk::glTextureBuffer:
case GLChunk::glTextureBufferEXT:
return Serialise_glTextureBufferEXT(ser, 0, eGL_NONE, eGL_NONE, 0);
case GLChunk::glProgramUniform1d:
case GLChunk::glProgramUniform1dEXT:
case GLChunk::glProgramUniform1dv:
case GLChunk::glProgramUniform1dvEXT:
case GLChunk::glProgramUniform1f:
case GLChunk::glProgramUniform1fEXT:
case GLChunk::glProgramUniform1fv:
case GLChunk::glProgramUniform1fvEXT:
case GLChunk::glProgramUniform1i:
case GLChunk::glProgramUniform1iEXT:
case GLChunk::glProgramUniform1iv:
case GLChunk::glProgramUniform1ivEXT:
case GLChunk::glProgramUniform1ui:
case GLChunk::glProgramUniform1uiEXT:
case GLChunk::glProgramUniform1uiv:
case GLChunk::glProgramUniform1uivEXT:
case GLChunk::glProgramUniform2d:
case GLChunk::glProgramUniform2dEXT:
case GLChunk::glProgramUniform2dv:
case GLChunk::glProgramUniform2dvEXT:
case GLChunk::glProgramUniform2f:
case GLChunk::glProgramUniform2fEXT:
case GLChunk::glProgramUniform2fv:
case GLChunk::glProgramUniform2fvEXT:
case GLChunk::glProgramUniform2i:
case GLChunk::glProgramUniform2iEXT:
case GLChunk::glProgramUniform2iv:
case GLChunk::glProgramUniform2ivEXT:
case GLChunk::glProgramUniform2ui:
case GLChunk::glProgramUniform2uiEXT:
case GLChunk::glProgramUniform2uiv:
case GLChunk::glProgramUniform2uivEXT:
case GLChunk::glProgramUniform3d:
case GLChunk::glProgramUniform3dEXT:
case GLChunk::glProgramUniform3dv:
case GLChunk::glProgramUniform3dvEXT:
case GLChunk::glProgramUniform3f:
case GLChunk::glProgramUniform3fEXT:
case GLChunk::glProgramUniform3fv:
case GLChunk::glProgramUniform3fvEXT:
case GLChunk::glProgramUniform3i:
case GLChunk::glProgramUniform3iEXT:
case GLChunk::glProgramUniform3iv:
case GLChunk::glProgramUniform3ivEXT:
case GLChunk::glProgramUniform3ui:
case GLChunk::glProgramUniform3uiEXT:
case GLChunk::glProgramUniform3uiv:
case GLChunk::glProgramUniform3uivEXT:
case GLChunk::glProgramUniform4d:
case GLChunk::glProgramUniform4dEXT:
case GLChunk::glProgramUniform4dv:
case GLChunk::glProgramUniform4dvEXT:
case GLChunk::glProgramUniform4f:
case GLChunk::glProgramUniform4fEXT:
case GLChunk::glProgramUniform4fv:
case GLChunk::glProgramUniform4fvEXT:
case GLChunk::glProgramUniform4i:
case GLChunk::glProgramUniform4iEXT:
case GLChunk::glProgramUniform4iv:
case GLChunk::glProgramUniform4ivEXT:
case GLChunk::glProgramUniform4ui:
case GLChunk::glProgramUniform4uiEXT:
case GLChunk::glProgramUniform4uiv:
case GLChunk::glProgramUniform4uivEXT:
case GLChunk::glUniform1d:
case GLChunk::glUniform1dv:
case GLChunk::glUniform1f:
case GLChunk::glUniform1fARB:
case GLChunk::glUniform1fv:
case GLChunk::glUniform1fvARB:
case GLChunk::glUniform1i:
case GLChunk::glUniform1iARB:
case GLChunk::glUniform1iv:
case GLChunk::glUniform1ivARB:
case GLChunk::glUniform1ui:
case GLChunk::glUniform1uiEXT:
case GLChunk::glUniform1uiv:
case GLChunk::glUniform1uivEXT:
case GLChunk::glUniform2d:
case GLChunk::glUniform2dv:
case GLChunk::glUniform2f:
case GLChunk::glUniform2fARB:
case GLChunk::glUniform2fv:
case GLChunk::glUniform2fvARB:
case GLChunk::glUniform2i:
case GLChunk::glUniform2iARB:
case GLChunk::glUniform2iv:
case GLChunk::glUniform2ivARB:
case GLChunk::glUniform2ui:
case GLChunk::glUniform2uiEXT:
case GLChunk::glUniform2uiv:
case GLChunk::glUniform2uivEXT:
case GLChunk::glUniform3d:
case GLChunk::glUniform3dv:
case GLChunk::glUniform3f:
case GLChunk::glUniform3fARB:
case GLChunk::glUniform3fv:
case GLChunk::glUniform3fvARB:
case GLChunk::glUniform3i:
case GLChunk::glUniform3iARB:
case GLChunk::glUniform3iv:
case GLChunk::glUniform3ivARB:
case GLChunk::glUniform3ui:
case GLChunk::glUniform3uiEXT:
case GLChunk::glUniform3uiv:
case GLChunk::glUniform3uivEXT:
case GLChunk::glUniform4d:
case GLChunk::glUniform4dv:
case GLChunk::glUniform4f:
case GLChunk::glUniform4fARB:
case GLChunk::glUniform4fv:
case GLChunk::glUniform4fvARB:
case GLChunk::glUniform4i:
case GLChunk::glUniform4iARB:
case GLChunk::glUniform4iv:
case GLChunk::glUniform4ivARB:
case GLChunk::glUniform4ui:
case GLChunk::glUniform4uiEXT:
case GLChunk::glUniform4uiv:
case GLChunk::glUniform4uivEXT:
return Serialise_glProgramUniformVector(ser, 0, 0, 0, 0, UNIFORM_UNKNOWN);
case GLChunk::glProgramUniformMatrix2dv:
case GLChunk::glProgramUniformMatrix2dvEXT:
case GLChunk::glProgramUniformMatrix2fv:
case GLChunk::glProgramUniformMatrix2fvEXT:
case GLChunk::glProgramUniformMatrix2x3dv:
case GLChunk::glProgramUniformMatrix2x3dvEXT:
case GLChunk::glProgramUniformMatrix2x3fv:
case GLChunk::glProgramUniformMatrix2x3fvEXT:
case GLChunk::glProgramUniformMatrix2x4dv:
case GLChunk::glProgramUniformMatrix2x4dvEXT:
case GLChunk::glProgramUniformMatrix2x4fv:
case GLChunk::glProgramUniformMatrix2x4fvEXT:
case GLChunk::glProgramUniformMatrix3dv:
case GLChunk::glProgramUniformMatrix3dvEXT:
case GLChunk::glProgramUniformMatrix3fv:
case GLChunk::glProgramUniformMatrix3fvEXT:
case GLChunk::glProgramUniformMatrix3x2dv:
case GLChunk::glProgramUniformMatrix3x2dvEXT:
case GLChunk::glProgramUniformMatrix3x2fv:
case GLChunk::glProgramUniformMatrix3x2fvEXT:
case GLChunk::glProgramUniformMatrix3x4dv:
case GLChunk::glProgramUniformMatrix3x4dvEXT:
case GLChunk::glProgramUniformMatrix3x4fv:
case GLChunk::glProgramUniformMatrix3x4fvEXT:
case GLChunk::glProgramUniformMatrix4dv:
case GLChunk::glProgramUniformMatrix4dvEXT:
case GLChunk::glProgramUniformMatrix4fv:
case GLChunk::glProgramUniformMatrix4fvEXT:
case GLChunk::glProgramUniformMatrix4x2dv:
case GLChunk::glProgramUniformMatrix4x2dvEXT:
case GLChunk::glProgramUniformMatrix4x2fv:
case GLChunk::glProgramUniformMatrix4x2fvEXT:
case GLChunk::glProgramUniformMatrix4x3dv:
case GLChunk::glProgramUniformMatrix4x3dvEXT:
case GLChunk::glProgramUniformMatrix4x3fv:
case GLChunk::glProgramUniformMatrix4x3fvEXT:
case GLChunk::glUniformMatrix2dv:
case GLChunk::glUniformMatrix2fv:
case GLChunk::glUniformMatrix2fvARB:
case GLChunk::glUniformMatrix2x3dv:
case GLChunk::glUniformMatrix2x3fv:
case GLChunk::glUniformMatrix2x4dv:
case GLChunk::glUniformMatrix2x4fv:
case GLChunk::glUniformMatrix3dv:
case GLChunk::glUniformMatrix3fv:
case GLChunk::glUniformMatrix3fvARB:
case GLChunk::glUniformMatrix3x2dv:
case GLChunk::glUniformMatrix3x2fv:
case GLChunk::glUniformMatrix3x4dv:
case GLChunk::glUniformMatrix3x4fv:
case GLChunk::glUniformMatrix4dv:
case GLChunk::glUniformMatrix4fv:
case GLChunk::glUniformMatrix4fvARB:
case GLChunk::glUniformMatrix4x2dv:
case GLChunk::glUniformMatrix4x2fv:
case GLChunk::glUniformMatrix4x3dv:
case GLChunk::glUniformMatrix4x3fv:
return Serialise_glProgramUniformMatrix(ser, 0, 0, 0, 0, 0, UNIFORM_UNKNOWN);
case GLChunk::vrapi_CreateTextureSwapChain:
case GLChunk::vrapi_CreateTextureSwapChain2:
// nothing to do, these chunks are just markers
return true;
case GLChunk::MakeContextCurrent:
// re-use the serialisation for beginning of the frame
return Serialise_BeginCaptureFrame(ser);
case GLChunk::ContextConfiguration: return Serialise_ContextConfiguration(ser, NULL);
case GLChunk::glIndirectSubCommand:
// this is a fake chunk generated at runtime as part of indirect draws.
// Just in case it gets exported and imported, completely ignore it.
return true;
case GLChunk::glShaderBinary: return Serialise_glShaderBinary(ser, 0, NULL, eGL_NONE, NULL, 0);
case GLChunk::glSpecializeShaderARB:
case GLChunk::glSpecializeShader:
return Serialise_glSpecializeShader(ser, 0, NULL, 0, NULL, NULL);
case GLChunk::glFinish: return Serialise_glFinish(ser);
case GLChunk::glFlush: return Serialise_glFlush(ser);
case GLChunk::glCreateMemoryObjectsEXT: return Serialise_glCreateMemoryObjectsEXT(ser, 0, NULL);
case GLChunk::glMemoryObjectParameterivEXT:
return Serialise_glMemoryObjectParameterivEXT(ser, 0, eGL_NONE, 0);
case GLChunk::glTexStorageMem1DEXT:
case GLChunk::glTextureStorageMem1DEXT:
return Serialise_glTextureStorageMem1DEXT(ser, 0, 0, eGL_NONE, 0, 0, 0);
case GLChunk::glTexStorageMem2DEXT:
case GLChunk::glTextureStorageMem2DEXT:
return Serialise_glTextureStorageMem2DEXT(ser, 0, 0, eGL_NONE, 0, 0, 0, 0);
case GLChunk::glTexStorageMem2DMultisampleEXT:
case GLChunk::glTextureStorageMem2DMultisampleEXT:
return Serialise_glTextureStorageMem2DMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0, GL_FALSE, 0, 0);
case GLChunk::glTexStorageMem3DEXT:
case GLChunk::glTextureStorageMem3DEXT:
return Serialise_glTextureStorageMem3DEXT(ser, 0, 0, eGL_NONE, 0, 0, 0, 0, 0);
case GLChunk::glTexStorageMem3DMultisampleEXT:
case GLChunk::glTextureStorageMem3DMultisampleEXT:
return Serialise_glTextureStorageMem3DMultisampleEXT(ser, 0, 0, eGL_NONE, 0, 0, 0, GL_FALSE,
0, 0);
case GLChunk::glBufferStorageMemEXT:
case GLChunk::glNamedBufferStorageMemEXT:
return Serialise_glNamedBufferStorageMemEXT(ser, 0, 0, 0, 0);
case GLChunk::glGenSemaphoresEXT: return Serialise_glGenSemaphoresEXT(ser, 0, NULL);
case GLChunk::glSemaphoreParameterui64vEXT:
return Serialise_glSemaphoreParameterui64vEXT(ser, 0, eGL_NONE, NULL);
case GLChunk::glWaitSemaphoreEXT:
return Serialise_glWaitSemaphoreEXT(ser, 0, 0, NULL, 0, NULL, NULL);
case GLChunk::glSignalSemaphoreEXT:
return Serialise_glSignalSemaphoreEXT(ser, 0, 0, NULL, 0, NULL, NULL);
case GLChunk::glImportMemoryFdEXT: return Serialise_glImportMemoryFdEXT(ser, 0, 0, eGL_NONE, 0);
case GLChunk::glImportSemaphoreFdEXT:
return Serialise_glImportSemaphoreFdEXT(ser, 0, eGL_NONE, 0);
case GLChunk::glImportMemoryWin32HandleEXT:
return Serialise_glImportMemoryWin32HandleEXT(ser, 0, 0, eGL_NONE, NULL);
case GLChunk::glImportMemoryWin32NameEXT:
return Serialise_glImportMemoryWin32NameEXT(ser, 0, 0, eGL_NONE, NULL);
case GLChunk::glImportSemaphoreWin32HandleEXT:
return Serialise_glImportSemaphoreWin32HandleEXT(ser, 0, eGL_NONE, NULL);
case GLChunk::glImportSemaphoreWin32NameEXT:
return Serialise_glImportSemaphoreWin32NameEXT(ser, 0, eGL_NONE, NULL);
case GLChunk::glAcquireKeyedMutexWin32EXT:
return Serialise_glAcquireKeyedMutexWin32EXT(ser, 0, 0, 0);
case GLChunk::glReleaseKeyedMutexWin32EXT:
return Serialise_glReleaseKeyedMutexWin32EXT(ser, 0, 0);
case GLChunk::SwapBuffers:
case GLChunk::wglSwapBuffers:
case GLChunk::glXSwapBuffers:
case GLChunk::CGLFlushDrawable:
case GLChunk::eglSwapBuffers:
case GLChunk::eglPostSubBufferNV:
case GLChunk::eglSwapBuffersWithDamageEXT:
case GLChunk::eglSwapBuffersWithDamageKHR:
return Serialise_Present(ser);
// these functions are not currently serialised - they do nothing on replay and are not
// serialised for information (it would be harmless and perhaps useful for the user to see
// where and how they're called).
case GLChunk::glGetActiveAtomicCounterBufferiv:
case GLChunk::glGetActiveAttrib:
case GLChunk::glGetActiveSubroutineName:
case GLChunk::glGetActiveSubroutineUniformiv:
case GLChunk::glGetActiveSubroutineUniformName:
case GLChunk::glGetActiveUniform:
case GLChunk::glGetActiveUniformBlockiv:
case GLChunk::glGetActiveUniformBlockName:
case GLChunk::glGetActiveUniformName:
case GLChunk::glGetActiveUniformsiv:
case GLChunk::glGetAttachedShaders:
case GLChunk::glGetAttribLocation:
case GLChunk::glGetBooleani_v:
case GLChunk::glGetBooleanIndexedvEXT:
case GLChunk::glGetBooleanv:
case GLChunk::glGetBufferParameteri64v:
case GLChunk::glGetBufferParameteriv:
case GLChunk::glGetBufferParameterivARB:
case GLChunk::glGetBufferPointerv:
case GLChunk::glGetBufferPointervARB:
case GLChunk::glGetBufferPointervOES:
case GLChunk::glGetBufferSubData:
case GLChunk::glGetBufferSubDataARB:
case GLChunk::glGetCompressedMultiTexImageEXT:
case GLChunk::glGetCompressedTexImage:
case GLChunk::glGetCompressedTexImageARB:
case GLChunk::glGetCompressedTextureImage:
case GLChunk::glGetCompressedTextureImageEXT:
case GLChunk::glGetCompressedTextureSubImage:
case GLChunk::glGetDebugMessageLog:
case GLChunk::glGetDebugMessageLogARB:
case GLChunk::glGetDebugMessageLogKHR:
case GLChunk::glGetDoublei_v:
case GLChunk::glGetDoublei_vEXT:
case GLChunk::glGetDoubleIndexedvEXT:
case GLChunk::glGetDoublev:
case GLChunk::glGetError:
case GLChunk::glGetFloati_v:
case GLChunk::glGetFloati_vEXT:
case GLChunk::glGetFloati_vNV:
case GLChunk::glGetFloati_vOES:
case GLChunk::glGetFloatIndexedvEXT:
case GLChunk::glGetFloatv:
case GLChunk::glGetFragDataIndex:
case GLChunk::glGetFragDataLocation:
case GLChunk::glGetFragDataLocationEXT:
case GLChunk::glGetFramebufferAttachmentParameteriv:
case GLChunk::glGetFramebufferAttachmentParameterivEXT:
case GLChunk::glGetFramebufferParameteriv:
case GLChunk::glGetFramebufferParameterivEXT:
case GLChunk::glGetGraphicsResetStatus:
case GLChunk::glGetGraphicsResetStatusARB:
case GLChunk::glGetGraphicsResetStatusEXT:
case GLChunk::glGetInteger64i_v:
case GLChunk::glGetInteger64v:
case GLChunk::glGetIntegeri_v:
case GLChunk::glGetIntegerIndexedvEXT:
case GLChunk::glGetIntegerv:
case GLChunk::glGetInternalformati64v:
case GLChunk::glGetInternalformativ:
case GLChunk::glGetMultisamplefv:
case GLChunk::glGetMultiTexImageEXT:
case GLChunk::glGetMultiTexLevelParameterfvEXT:
case GLChunk::glGetMultiTexLevelParameterivEXT:
case GLChunk::glGetMultiTexParameterfvEXT:
case GLChunk::glGetMultiTexParameterIivEXT:
case GLChunk::glGetMultiTexParameterIuivEXT:
case GLChunk::glGetMultiTexParameterivEXT:
case GLChunk::glGetNamedBufferParameteri64v:
case GLChunk::glGetNamedBufferParameteriv:
case GLChunk::glGetNamedBufferParameterivEXT:
case GLChunk::glGetNamedBufferPointerv:
case GLChunk::glGetNamedBufferPointervEXT:
case GLChunk::glGetNamedBufferSubData:
case GLChunk::glGetNamedBufferSubDataEXT:
case GLChunk::glGetNamedFramebufferAttachmentParameteriv:
case GLChunk::glGetNamedFramebufferAttachmentParameterivEXT:
case GLChunk::glGetNamedFramebufferParameteriv:
case GLChunk::glGetNamedFramebufferParameterivEXT:
case GLChunk::glGetNamedProgramivEXT:
case GLChunk::glGetNamedRenderbufferParameteriv:
case GLChunk::glGetNamedRenderbufferParameterivEXT:
case GLChunk::glGetNamedStringARB:
case GLChunk::glGetNamedStringivARB:
case GLChunk::glGetnCompressedTexImage:
case GLChunk::glGetnCompressedTexImageARB:
case GLChunk::glGetnTexImage:
case GLChunk::glGetnTexImageARB:
case GLChunk::glGetnUniformdv:
case GLChunk::glGetnUniformdvARB:
case GLChunk::glGetnUniformfv:
case GLChunk::glGetnUniformfvARB:
case GLChunk::glGetnUniformfvEXT:
case GLChunk::glGetnUniformiv:
case GLChunk::glGetnUniformivARB:
case GLChunk::glGetnUniformivEXT:
case GLChunk::glGetnUniformuiv:
case GLChunk::glGetnUniformuivARB:
case GLChunk::glGetObjectLabel:
case GLChunk::glGetObjectLabelEXT:
case GLChunk::glGetObjectLabelKHR:
case GLChunk::glGetObjectPtrLabel:
case GLChunk::glGetObjectPtrLabelKHR:
case GLChunk::glGetPointeri_vEXT:
case GLChunk::glGetPointerIndexedvEXT:
case GLChunk::glGetPointerv:
case GLChunk::glGetPointervKHR:
case GLChunk::glGetProgramBinary:
case GLChunk::glGetProgramInfoLog:
case GLChunk::glGetProgramInterfaceiv:
case GLChunk::glGetProgramiv:
case GLChunk::glGetProgramPipelineInfoLog:
case GLChunk::glGetProgramPipelineInfoLogEXT:
case GLChunk::glGetProgramPipelineiv:
case GLChunk::glGetProgramPipelineivEXT:
case GLChunk::glGetProgramResourceIndex:
case GLChunk::glGetProgramResourceiv:
case GLChunk::glGetProgramResourceLocation:
case GLChunk::glGetProgramResourceLocationIndex:
case GLChunk::glGetProgramResourceName:
case GLChunk::glGetProgramStageiv:
case GLChunk::glGetQueryBufferObjecti64v:
case GLChunk::glGetQueryBufferObjectiv:
case GLChunk::glGetQueryBufferObjectui64v:
case GLChunk::glGetQueryBufferObjectuiv:
case GLChunk::glGetQueryIndexediv:
case GLChunk::glGetQueryiv:
case GLChunk::glGetQueryivARB:
case GLChunk::glGetQueryivEXT:
case GLChunk::glGetQueryObjecti64v:
case GLChunk::glGetQueryObjecti64vEXT:
case GLChunk::glGetQueryObjectiv:
case GLChunk::glGetQueryObjectivARB:
case GLChunk::glGetQueryObjectivEXT:
case GLChunk::glGetQueryObjectui64v:
case GLChunk::glGetQueryObjectui64vEXT:
case GLChunk::glGetQueryObjectuiv:
case GLChunk::glGetQueryObjectuivARB:
case GLChunk::glGetQueryObjectuivEXT:
case GLChunk::glGetRenderbufferParameteriv:
case GLChunk::glGetRenderbufferParameterivEXT:
case GLChunk::glGetSamplerParameterfv:
case GLChunk::glGetSamplerParameterIiv:
case GLChunk::glGetSamplerParameterIivEXT:
case GLChunk::glGetSamplerParameterIivOES:
case GLChunk::glGetSamplerParameterIuiv:
case GLChunk::glGetSamplerParameterIuivEXT:
case GLChunk::glGetSamplerParameterIuivOES:
case GLChunk::glGetSamplerParameteriv:
case GLChunk::glGetShaderInfoLog:
case GLChunk::glGetShaderiv:
case GLChunk::glGetShaderPrecisionFormat:
case GLChunk::glGetShaderSource:
case GLChunk::glGetString:
case GLChunk::glGetStringi:
case GLChunk::glGetSubroutineIndex:
case GLChunk::glGetSubroutineUniformLocation:
case GLChunk::glGetSynciv:
case GLChunk::glGetTexImage:
case GLChunk::glGetTexLevelParameterfv:
case GLChunk::glGetTexLevelParameteriv:
case GLChunk::glGetTexParameterfv:
case GLChunk::glGetTexParameterIiv:
case GLChunk::glGetTexParameterIivEXT:
case GLChunk::glGetTexParameterIivOES:
case GLChunk::glGetTexParameterIuiv:
case GLChunk::glGetTexParameterIuivEXT:
case GLChunk::glGetTexParameterIuivOES:
case GLChunk::glGetTexParameteriv:
case GLChunk::glGetTextureImage:
case GLChunk::glGetTextureImageEXT:
case GLChunk::glGetTextureLevelParameterfv:
case GLChunk::glGetTextureLevelParameterfvEXT:
case GLChunk::glGetTextureLevelParameteriv:
case GLChunk::glGetTextureLevelParameterivEXT:
case GLChunk::glGetTextureParameterfv:
case GLChunk::glGetTextureParameterfvEXT:
case GLChunk::glGetTextureParameterIiv:
case GLChunk::glGetTextureParameterIivEXT:
case GLChunk::glGetTextureParameterIuiv:
case GLChunk::glGetTextureParameterIuivEXT:
case GLChunk::glGetTextureParameteriv:
case GLChunk::glGetTextureParameterivEXT:
case GLChunk::glGetTextureSubImage:
case GLChunk::glGetTransformFeedbacki_v:
case GLChunk::glGetTransformFeedbacki64_v:
case GLChunk::glGetTransformFeedbackiv:
case GLChunk::glGetTransformFeedbackVarying:
case GLChunk::glGetTransformFeedbackVaryingEXT:
case GLChunk::glGetUniformBlockIndex:
case GLChunk::glGetUniformdv:
case GLChunk::glGetUniformfv:
case GLChunk::glGetUniformIndices:
case GLChunk::glGetUniformiv:
case GLChunk::glGetUniformLocation:
case GLChunk::glGetUniformSubroutineuiv:
case GLChunk::glGetUniformuiv:
case GLChunk::glGetUniformuivEXT:
case GLChunk::glGetVertexArrayIndexed64iv:
case GLChunk::glGetVertexArrayIndexediv:
case GLChunk::glGetVertexArrayIntegeri_vEXT:
case GLChunk::glGetVertexArrayIntegervEXT:
case GLChunk::glGetVertexArrayiv:
case GLChunk::glGetVertexArrayPointeri_vEXT:
case GLChunk::glGetVertexArrayPointervEXT:
case GLChunk::glGetVertexAttribdv:
case GLChunk::glGetVertexAttribfv:
case GLChunk::glGetVertexAttribIiv:
case GLChunk::glGetVertexAttribIivEXT:
case GLChunk::glGetVertexAttribIuiv:
case GLChunk::glGetVertexAttribIuivEXT:
case GLChunk::glGetVertexAttribiv:
case GLChunk::glGetVertexAttribLdv:
case GLChunk::glGetVertexAttribLdvEXT:
case GLChunk::glGetVertexAttribPointerv:
case GLChunk::glIsBuffer:
case GLChunk::glIsBufferARB:
case GLChunk::glIsEnabled:
case GLChunk::glIsEnabledi:
case GLChunk::glIsEnablediEXT:
case GLChunk::glIsEnabledIndexedEXT:
case GLChunk::glIsEnablediNV:
case GLChunk::glIsEnablediOES:
case GLChunk::glIsFramebuffer:
case GLChunk::glIsFramebufferEXT:
case GLChunk::glIsNamedStringARB:
case GLChunk::glIsProgram:
case GLChunk::glIsProgramPipeline:
case GLChunk::glIsProgramPipelineEXT:
case GLChunk::glIsQuery:
case GLChunk::glIsQueryARB:
case GLChunk::glIsQueryEXT:
case GLChunk::glIsRenderbuffer:
case GLChunk::glIsRenderbufferEXT:
case GLChunk::glIsSampler:
case GLChunk::glIsShader:
case GLChunk::glIsSync:
case GLChunk::glIsTexture:
case GLChunk::glIsTransformFeedback:
case GLChunk::glIsVertexArray:
case GLChunk::glIsVertexArrayOES:
case GLChunk::glValidateProgram:
case GLChunk::glValidateProgramPipeline:
case GLChunk::glValidateProgramPipelineEXT:
case GLChunk::glCheckFramebufferStatus:
case GLChunk::glCheckFramebufferStatusEXT:
case GLChunk::glCheckNamedFramebufferStatus:
case GLChunk::glCheckNamedFramebufferStatusEXT:
case GLChunk::glReadnPixels:
case GLChunk::glReadnPixelsARB:
case GLChunk::glReadnPixelsEXT:
case GLChunk::glClampColor:
case GLChunk::glClampColorARB:
case GLChunk::glReadPixels:
case GLChunk::glDeleteBuffers:
case GLChunk::glDeleteBuffersARB:
case GLChunk::glDeleteFramebuffers:
case GLChunk::glDeleteFramebuffersEXT:
case GLChunk::glDeleteProgram:
case GLChunk::glDeleteProgramPipelines:
case GLChunk::glDeleteProgramPipelinesEXT:
case GLChunk::glDeleteQueries:
case GLChunk::glDeleteQueriesARB:
case GLChunk::glDeleteQueriesEXT:
case GLChunk::glDeleteRenderbuffers:
case GLChunk::glDeleteRenderbuffersEXT:
case GLChunk::glDeleteSamplers:
case GLChunk::glDeleteShader:
case GLChunk::glDeleteSync:
case GLChunk::glDeleteTextures:
case GLChunk::glDeleteTransformFeedbacks:
case GLChunk::glDeleteVertexArrays:
case GLChunk::glDeleteVertexArraysOES:
case GLChunk::glBindRenderbufferEXT:
case GLChunk::glBindRenderbuffer:
case GLChunk::glActiveShaderProgram:
case GLChunk::glActiveShaderProgramEXT:
case GLChunk::glProgramBinary:
case GLChunk::glReleaseShaderCompiler:
case GLChunk::glFrameTerminatorGREMEDY:
case GLChunk::glInvalidateBufferData:
case GLChunk::glInvalidateBufferSubData:
case GLChunk::glInvalidateNamedFramebufferSubData:
case GLChunk::glInvalidateSubFramebuffer:
case GLChunk::glInvalidateTexImage:
case GLChunk::glInvalidateTexSubImage:
case GLChunk::glDebugMessageCallback:
case GLChunk::glDebugMessageCallbackARB:
case GLChunk::glDebugMessageCallbackKHR:
case GLChunk::glDebugMessageControl:
case GLChunk::glDebugMessageControlARB:
case GLChunk::glDebugMessageControlKHR:
case GLChunk::glMapBuffer:
case GLChunk::glMapBufferARB:
case GLChunk::glMapBufferOES:
case GLChunk::glMapBufferRange:
case GLChunk::glMapNamedBuffer:
case GLChunk::glMapNamedBufferEXT:
case GLChunk::glMapNamedBufferRange:
case GLChunk::glMapNamedBufferRangeEXT:
case GLChunk::wglDXSetResourceShareHandleNV:
case GLChunk::wglDXOpenDeviceNV:
case GLChunk::wglDXCloseDeviceNV:
case GLChunk::wglDXUnregisterObjectNV:
case GLChunk::wglDXObjectAccessNV:
case GLChunk::wglDXUnlockObjectsNV:
case GLChunk::glMaxShaderCompilerThreadsARB:
case GLChunk::glMaxShaderCompilerThreadsKHR:
case GLChunk::glGetUnsignedBytevEXT:
case GLChunk::glGetUnsignedBytei_vEXT:
case GLChunk::glDeleteMemoryObjectsEXT:
case GLChunk::glIsMemoryObjectEXT:
case GLChunk::glGetMemoryObjectParameterivEXT:
case GLChunk::glDeleteSemaphoresEXT:
case GLChunk::glIsSemaphoreEXT:
case GLChunk::glGetSemaphoreParameterui64vEXT:
case GLChunk::glBeginPerfQueryINTEL:
case GLChunk::glCreatePerfQueryINTEL:
case GLChunk::glDeletePerfQueryINTEL:
case GLChunk::glEndPerfQueryINTEL:
case GLChunk::glGetFirstPerfQueryIdINTEL:
case GLChunk::glGetNextPerfQueryIdINTEL:
case GLChunk::glGetPerfCounterInfoINTEL:
case GLChunk::glGetPerfQueryDataINTEL:
case GLChunk::glGetPerfQueryIdByNameINTEL:
case GLChunk::glGetPerfQueryInfoINTEL:
case GLChunk::Max:
RDCERR("Unexpected chunk %s, or missing case for processing! Skipping...",
ToStr(chunk).c_str());
ser.SkipCurrentChunk();
return false;
}
return false;
}
ReplayStatus WrappedOpenGL::ContextReplayLog(CaptureState readType, uint32_t startEventID,
uint32_t endEventID, bool partial)
{
m_FrameReader->SetOffset(0);
ReadSerialiser ser(m_FrameReader, Ownership::Nothing);
ser.SetStringDatabase(&m_StringDB);
ser.SetUserData(GetResourceManager());
ser.SetVersion(m_SectionVersion);
SDFile *prevFile = m_StructuredFile;
if(IsLoading(m_State) || IsStructuredExporting(m_State))
{
ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State));
ser.GetStructuredFile().Swap(*m_StructuredFile);
m_StructuredFile = &ser.GetStructuredFile();
}
SystemChunk header = ser.ReadChunk<SystemChunk>();
RDCASSERTEQUAL(header, SystemChunk::CaptureBegin);
if(IsActiveReplaying(m_State) && !partial)
{
for(size_t i = 0; i < 8; i++)
{
GLenum q = QueryEnum(i);
if(q == eGL_NONE)
break;
int indices = IsGLES ? 1 : 8; // GLES does not support indices
for(int j = 0; j < indices; j++)
{
if(m_ActiveQueries[i][j])
{
if(IsGLES)
GL.glEndQuery(q);
else
GL.glEndQueryIndexed(q, j);
m_ActiveQueries[i][j] = false;
}
}
}
if(m_ActiveConditional)
{
GL.glEndConditionalRender();
m_ActiveConditional = false;
}
if(m_ActiveFeedback)
{
GL.glEndTransformFeedback();
m_ActiveFeedback = false;
}
}
if(partial)
ser.SkipCurrentChunk();
else
Serialise_BeginCaptureFrame(ser);
ser.EndChunk();
m_CurEvents.clear();
if(IsActiveReplaying(m_State))
{
APIEvent ev = GetEvent(startEventID);
m_CurEventID = ev.eventId;
if(partial)
ser.GetReader()->SetOffset(ev.fileOffset);
m_FirstEventID = startEventID;
m_LastEventID = endEventID;
}
else
{
m_CurEventID = 1;
m_CurDrawcallID = 1;
m_FirstEventID = 0;
m_LastEventID = ~0U;
}
uint64_t startOffset = ser.GetReader()->GetOffset();
for(;;)
{
if(IsActiveReplaying(m_State) && m_CurEventID > endEventID)
{
// we can just break out if we've done all the events desired.
break;
}
m_CurChunkOffset = ser.GetReader()->GetOffset();
GLChunk chunktype = ser.ReadChunk<GLChunk>();
if(ser.GetReader()->IsErrored())
return ReplayStatus::APIDataCorrupted;
m_ChunkMetadata = ser.ChunkMetadata();
bool success = ContextProcessChunk(ser, chunktype);
ser.EndChunk();
if(ser.GetReader()->IsErrored())
return ReplayStatus::APIDataCorrupted;
// if there wasn't a serialisation error, but the chunk didn't succeed, then it's an API replay
// failure.
if(!success)
return m_FailedReplayStatus;
RenderDoc::Inst().SetProgress(
LoadProgress::FrameEventsRead,
float(m_CurChunkOffset - startOffset) / float(ser.GetReader()->GetSize()));
if((SystemChunk)chunktype == SystemChunk::CaptureEnd)
break;
m_LastChunk = chunktype;
m_CurEventID++;
}
// swap the structure back now that we've accumulated the frame as well.
if(IsLoading(m_State) || IsStructuredExporting(m_State))
ser.GetStructuredFile().Swap(*prevFile);
m_StructuredFile = prevFile;
if(IsLoading(m_State))
{
GetReplay()->WriteFrameRecord().drawcallList = m_ParentDrawcall.children;
GetReplay()->WriteFrameRecord().frameInfo.debugMessages = GetDebugMessages();
SetupDrawcallPointers(m_Drawcalls, GetReplay()->WriteFrameRecord().drawcallList);
// it's easier to remove duplicate usages here than check it as we go.
// this means if textures are bound in multiple places in the same draw
// we don't have duplicate uses
for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it)
{
rdcarray<EventUsage> &v = it->second;
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()) - v.begin(), ~0U);
}
}
return ReplayStatus::Succeeded;
}
bool WrappedOpenGL::ContextProcessChunk(ReadSerialiser &ser, GLChunk chunk)
{
m_AddedDrawcall = false;
bool success = ProcessChunk(ser, chunk);
if(!success)
return false;
if(IsLoading(m_State))
{
switch(chunk)
{
case GLChunk::glStringMarkerGREMEDY:
case GLChunk::glInsertEventMarkerEXT:
case GLChunk::glDebugMessageInsert:
case GLChunk::glDebugMessageInsertARB:
case GLChunk::glDebugMessageInsertKHR:
// no push/pop necessary
break;
case GLChunk::glPushGroupMarkerEXT:
case GLChunk::glPushDebugGroup:
case GLChunk::glPushDebugGroupKHR:
{
// push down the drawcallstack to the latest drawcall
m_DrawcallStack.push_back(&m_DrawcallStack.back()->children.back());
break;
}
case GLChunk::glPopGroupMarkerEXT:
case GLChunk::glPopDebugGroup:
case GLChunk::glPopDebugGroupKHR:
{
// refuse to pop off further than the root drawcall (mismatched begin/end events e.g.)
if(m_DrawcallStack.size() > 1)
m_DrawcallStack.pop_back();
break;
}
default: break;
}
if(!m_AddedDrawcall)
AddEvent();
}
m_AddedDrawcall = false;
return true;
}
void WrappedOpenGL::AddUsage(const DrawcallDescription &d)
{
DrawFlags DrawDispatchMask = DrawFlags::Drawcall | DrawFlags::Dispatch;
if(!(d.flags & DrawDispatchMask))
return;
GLResourceManager *rm = GetResourceManager();
ContextPair &ctx = GetCtx();
uint32_t e = d.eventId;
//////////////////////////////
// Input
if(d.flags & DrawFlags::Indexed)
{
GLuint ibuffer = 0;
GL.glGetIntegerv(eGL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint *)&ibuffer);
if(ibuffer)
m_ResourceUses[rm->GetID(BufferRes(ctx, ibuffer))].push_back(
EventUsage(e, ResourceUsage::IndexBuffer));
}
// Vertex buffers and attributes
GLint numVBufferBindings = GetNumVertexBuffers();
for(GLuint i = 0; i < (GLuint)numVBufferBindings; i++)
{
GLuint buffer = GetBoundVertexBuffer(i);
if(buffer)
m_ResourceUses[rm->GetID(BufferRes(ctx, buffer))].push_back(
EventUsage(e, ResourceUsage::VertexBuffer));
}
//////////////////////////////
// Shaders
{
GLRenderState rs;
rs.FetchState(this);
ShaderReflection *refl[6] = {NULL};
ShaderBindpointMapping mapping[6];
GLuint curProg = 0;
GL.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&curProg);
if(curProg == 0)
{
GL.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&curProg);
if(curProg == 0)
{
// no program bound at this draw
}
else
{
auto &pipeDetails = m_Pipelines[rm->GetID(ProgramPipeRes(ctx, curProg))];
for(size_t i = 0; i < ARRAY_COUNT(pipeDetails.stageShaders); i++)
{
if(pipeDetails.stageShaders[i] != ResourceId())
{
curProg = rm->GetCurrentResource(pipeDetails.stagePrograms[i]).name;
refl[i] = &m_Shaders[pipeDetails.stageShaders[i]].reflection;
GetBindpointMapping(curProg, (int)i, refl[i], mapping[i]);
}
}
}
}
else
{
auto &progDetails = m_Programs[rm->GetID(ProgramRes(ctx, curProg))];
for(size_t i = 0; i < ARRAY_COUNT(progDetails.stageShaders); i++)
{
if(progDetails.stageShaders[i] != ResourceId())
{
refl[i] = &m_Shaders[progDetails.stageShaders[i]].reflection;
GetBindpointMapping(curProg, (int)i, refl[i], mapping[i]);
}
}
}
for(size_t i = 0; i < ARRAY_COUNT(refl); i++)
{
EventUsage cb = EventUsage(e, CBUsage(i));
EventUsage ro = EventUsage(e, ResUsage(i));
EventUsage rw = EventUsage(e, RWResUsage(i));
if(refl[i])
{
for(const ConstantBlock &cblock : refl[i]->constantBlocks)
{
if(!cblock.bufferBacked)
continue;
if(cblock.bindPoint < 0 || cblock.bindPoint >= mapping[i].constantBlocks.count())
continue;
int32_t bind = mapping[i].constantBlocks[cblock.bindPoint].bind;
if(rs.UniformBinding[bind].res.name)
m_ResourceUses[rm->GetID(rs.UniformBinding[bind].res)].push_back(cb);
}
for(const ShaderResource &res : refl[i]->readWriteResources)
{
int32_t bind = mapping[i].readWriteResources[res.bindPoint].bind;
if(res.isTexture)
{
if(rs.Images[bind].res.name)
m_ResourceUses[rm->GetID(rs.Images[bind].res)].push_back(rw);
}
else
{
if(res.variableType.descriptor.columns == 1 && res.variableType.descriptor.rows == 1 &&
res.variableType.descriptor.type == VarType::UInt)
{
if(rs.AtomicCounter[bind].res.name)
m_ResourceUses[rm->GetID(rs.AtomicCounter[bind].res)].push_back(rw);
}
else
{
if(rs.ShaderStorage[bind].res.name)
m_ResourceUses[rm->GetID(rs.ShaderStorage[bind].res)].push_back(rw);
}
}
}
for(const ShaderResource &res : refl[i]->readOnlyResources)
{
int32_t bind = mapping[i].readOnlyResources[res.bindPoint].bind;
GLResource *texList = NULL;
const int32_t listSize = (int32_t)ARRAY_COUNT(rs.Tex2D);
;
switch(res.resType)
{
case TextureType::Unknown: texList = NULL; break;
case TextureType::Buffer: texList = rs.TexBuffer; break;
case TextureType::Texture1D: texList = rs.Tex1D; break;
case TextureType::Texture1DArray: texList = rs.Tex1DArray; break;
case TextureType::Texture2D: texList = rs.Tex2D; break;
case TextureType::TextureRect: texList = rs.TexRect; break;
case TextureType::Texture2DArray: texList = rs.Tex2DArray; break;
case TextureType::Texture2DMS: texList = rs.Tex2DMS; break;
case TextureType::Texture2DMSArray: texList = rs.Tex2DMSArray; break;
case TextureType::Texture3D: texList = rs.Tex3D; break;
case TextureType::TextureCube: texList = rs.TexCube; break;
case TextureType::TextureCubeArray: texList = rs.TexCubeArray; break;
case TextureType::Count: RDCERR("Invalid shader resource type"); break;
}
if(texList != NULL && bind >= 0 && bind < listSize && texList[bind].name != 0)
m_ResourceUses[rm->GetID(texList[bind])].push_back(ro);
}
}
}
}
//////////////////////////////
// Feedback
GLint maxCount = 0;
GL.glGetIntegerv(eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxCount);
for(int i = 0; i < maxCount; i++)
{
GLuint buffer = 0;
GL.glGetIntegeri_v(eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING, i, (GLint *)&buffer);
if(buffer)
m_ResourceUses[rm->GetID(BufferRes(ctx, buffer))].push_back(
EventUsage(e, ResourceUsage::StreamOut));
}
//////////////////////////////
// FBO
GLint numCols = 8;
GL.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols);
GLuint attachment = 0;
GLenum type = eGL_TEXTURE;
for(GLint i = 0; i < numCols; i++)
{
type = eGL_TEXTURE;
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&attachment);
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
if(attachment)
{
if(type == eGL_TEXTURE)
m_ResourceUses[rm->GetID(TextureRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::ColorTarget));
else
m_ResourceUses[rm->GetID(RenderbufferRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::ColorTarget));
}
}
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&attachment);
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
if(attachment)
{
if(type == eGL_TEXTURE)
m_ResourceUses[rm->GetID(TextureRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::DepthStencilTarget));
else
m_ResourceUses[rm->GetID(RenderbufferRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::DepthStencilTarget));
}
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&attachment);
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
if(attachment)
{
if(type == eGL_TEXTURE)
m_ResourceUses[rm->GetID(TextureRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::DepthStencilTarget));
else
m_ResourceUses[rm->GetID(RenderbufferRes(ctx, attachment))].push_back(
EventUsage(e, ResourceUsage::DepthStencilTarget));
}
}
void WrappedOpenGL::AddDrawcall(const DrawcallDescription &d, bool hasEvents)
{
m_AddedDrawcall = true;
WrappedOpenGL *context = this;
DrawcallDescription draw = d;
draw.eventId = m_CurEventID;
draw.drawcallId = m_CurDrawcallID;
GLenum type;
GLuint curCol[8] = {0};
GLuint curDepth = 0;
{
GLint numCols = 8;
GL.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols);
RDCEraseEl(draw.outputs);
for(GLint i = 0; i < RDCMIN(numCols, 8); i++)
{
type = eGL_TEXTURE;
GL.glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&curCol[i]);
GL.glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
if(type == eGL_TEXTURE)
draw.outputs[i] = GetResourceManager()->GetOriginalID(
GetResourceManager()->GetID(TextureRes(GetCtx(), curCol[i])));
else
draw.outputs[i] = GetResourceManager()->GetOriginalID(
GetResourceManager()->GetID(RenderbufferRes(GetCtx(), curCol[i])));
}
type = eGL_TEXTURE;
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&curDepth);
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
if(type == eGL_TEXTURE)
draw.depthOut = GetResourceManager()->GetOriginalID(
GetResourceManager()->GetID(TextureRes(GetCtx(), curDepth)));
else
draw.depthOut = GetResourceManager()->GetOriginalID(
GetResourceManager()->GetID(RenderbufferRes(GetCtx(), curDepth)));
}
// markers don't increment drawcall ID
DrawFlags MarkerMask = DrawFlags::SetMarker | DrawFlags::PushMarker | DrawFlags::MultiDraw;
if(!(draw.flags & MarkerMask))
m_CurDrawcallID++;
if(hasEvents)
{
draw.events = m_CurEvents;
m_CurEvents.clear();
}
AddUsage(draw);
// should have at least the root drawcall here, push this drawcall
// onto the back's children list.
if(!context->m_DrawcallStack.empty())
m_DrawcallStack.back()->children.push_back(draw);
else
RDCERR("Somehow lost drawcall stack!");
}
void WrappedOpenGL::AddEvent()
{
APIEvent apievent;
apievent.fileOffset = m_CurChunkOffset;
apievent.eventId = m_CurEventID;
apievent.chunkIndex = uint32_t(m_StructuredFile->chunks.size() - 1);
apievent.callstack = m_ChunkMetadata.callstack;
m_CurEvents.push_back(apievent);
if(IsLoading(m_State))
{
m_Events.resize(apievent.eventId + 1);
m_Events[apievent.eventId] = apievent;
}
}
const APIEvent &WrappedOpenGL::GetEvent(uint32_t eventId)
{
// start at where the requested eventId would be
size_t idx = eventId;
// find the next valid event (some may be skipped)
while(idx < m_Events.size() - 1 && m_Events[idx].eventId == 0)
idx++;
return m_Events[RDCMIN(idx, m_Events.size() - 1)];
}
const DrawcallDescription *WrappedOpenGL::GetDrawcall(uint32_t eventId)
{
if(eventId >= m_Drawcalls.size())
return NULL;
return m_Drawcalls[eventId];
}
void WrappedOpenGL::ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType)
{
bool partial = true;
if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full))
{
startEventID = 1;
partial = false;
}
if(!partial)
{
GLMarkerRegion apply("!!!!RenderDoc Internal: ApplyInitialContents");
GetResourceManager()->ApplyInitialContents();
m_WasActiveFeedback = false;
}
m_State = CaptureState::ActiveReplaying;
GLMarkerRegion::Set(StringFormat::Fmt("!!!!RenderDoc Internal: Replay %d (%d): %u->%u",
(int)replayType, (int)partial, startEventID, endEventID));
m_ReplayEventCount = 0;
ReplayStatus status = ReplayStatus::Succeeded;
if(replayType == eReplay_Full)
status = ContextReplayLog(m_State, startEventID, endEventID, partial);
else if(replayType == eReplay_WithoutDraw)
status = ContextReplayLog(m_State, startEventID, RDCMAX(1U, endEventID) - 1, partial);
else if(replayType == eReplay_OnlyDraw)
status = ContextReplayLog(m_State, endEventID, endEventID, partial);
else
RDCFATAL("Unexpected replay type");
RDCASSERTEQUAL(status, ReplayStatus::Succeeded);
// make sure to end any unbalanced replay events if we stopped in the middle of a frame
for(int i = 0; m_ReplayMarkers && i < m_ReplayEventCount; i++)
GLMarkerRegion::End();
GLMarkerRegion::Set("!!!!RenderDoc Internal: Done replay");
}