mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-27 09:51:40 +00:00
5260 lines
189 KiB
C++
5260 lines
189 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015-2017 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 "data/glsl_shaders.h"
|
|
#include "driver/shaders/spirv/spirv_common.h"
|
|
#include "jpeg-compressor/jpge.h"
|
|
#include "maths/matrix.h"
|
|
#include "maths/vec.h"
|
|
#include "serialise/rdcfile.h"
|
|
#include "stb/stb_truetype.h"
|
|
#include "strings/string_utils.h"
|
|
|
|
#define OPENGL 1
|
|
#include "data/glsl/debuguniforms.h"
|
|
|
|
std::map<uint64_t, GLWindowingData> WrappedOpenGL::m_ActiveContexts;
|
|
|
|
const int firstChar = int(' ') + 1;
|
|
const int lastChar = 127;
|
|
const int numChars = lastChar - firstChar;
|
|
const float charPixelHeight = 20.0f;
|
|
|
|
stbtt_bakedchar chardata[numChars];
|
|
|
|
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_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_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_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_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_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_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_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_pixel_buffer_object");
|
|
m_GLExtensions.push_back("GL_EXT_point_parameters");
|
|
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_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_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_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_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_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_ARB_ES3_2_compatibility
|
|
* GL_ARB_gpu_shader_int64
|
|
* GL_ARB_parallel_shader_compile
|
|
* GL_ARB_sample_locations
|
|
* GL_ARB_texture_filter_minmax
|
|
|
|
************************************************************************/
|
|
|
|
/************************************************************************
|
|
|
|
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_program
|
|
* 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_Cg_shader
|
|
* 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_minmax");
|
|
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_copy_image");
|
|
m_GLESExtensions.push_back("GL_EXT_debug_label");
|
|
m_GLESExtensions.push_back("GL_EXT_debug_marker");
|
|
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_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_multisampled_render_to_texture");
|
|
m_GLESExtensions.push_back("GL_EXT_primitive_bounding_box");
|
|
m_GLESExtensions.push_back("GL_EXT_pvrtc_sRGB");
|
|
m_GLESExtensions.push_back("GL_EXT_robustness");
|
|
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_dxt1");
|
|
m_GLESExtensions.push_back("GL_EXT_texture_compression_s3tc");
|
|
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_norm16");
|
|
m_GLESExtensions.push_back("GL_EXT_texture_rg");
|
|
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_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_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_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_fbo_render_mipmap");
|
|
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_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_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");
|
|
|
|
// 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());
|
|
}
|
|
|
|
WrappedOpenGL::WrappedOpenGL(const GLHookSet &funcs, GLPlatform &platform)
|
|
: m_Real(funcs),
|
|
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(RDC_OpenGL);
|
|
|
|
m_Replay.SetDriver(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_SectionVersion = GLInitParams::CurrentVersion;
|
|
|
|
m_FrameCounter = 0;
|
|
m_NoCtxFrames = 0;
|
|
m_FailedFrame = 0;
|
|
m_FailedReason = CaptureSucceeded;
|
|
m_Failures = 0;
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
|
|
m_AppControlledCapture = false;
|
|
|
|
m_RealDebugFunc = NULL;
|
|
m_RealDebugFuncParam = NULL;
|
|
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;
|
|
|
|
GLMarkerRegion::gl = &m_Real;
|
|
|
|
RegisterDebugCallback();
|
|
}
|
|
else
|
|
{
|
|
m_State = CaptureState::BackgroundCapturing;
|
|
}
|
|
|
|
m_DeviceRecord = NULL;
|
|
|
|
m_ResourceManager = new GLResourceManager(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->SpecialResource = true;
|
|
|
|
m_ContextRecord = GetResourceManager()->AddResourceRecord(m_ContextResourceID);
|
|
m_ContextRecord->DataInSerialiser = false;
|
|
m_ContextRecord->Length = 0;
|
|
m_ContextRecord->SpecialResource = true;
|
|
|
|
// register VAO 0 as a special VAO, so that it can be tracked if the app uses it
|
|
// we immediately mark it dirty since the vertex array tracking functions expect a proper VAO
|
|
m_FakeVAOID = GetResourceManager()->RegisterResource(VertexArrayRes(NULL, 0));
|
|
GetResourceManager()->AddResourceRecord(m_FakeVAOID);
|
|
GetResourceManager()->MarkDirtyResource(m_FakeVAOID);
|
|
}
|
|
else
|
|
{
|
|
m_DeviceRecord = m_ContextRecord = NULL;
|
|
|
|
ResourceIDGen::SetReplayResourceIDs();
|
|
|
|
InitSPIRVCompiler();
|
|
RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler);
|
|
}
|
|
|
|
m_FakeBB_FBO = 0;
|
|
m_FakeBB_Color = 0;
|
|
m_FakeBB_DepthStencil = 0;
|
|
m_FakeVAO = 0;
|
|
m_FakeIdxSize = 0;
|
|
|
|
m_CurChunkOffset = 0;
|
|
m_AddedDrawcall = false;
|
|
}
|
|
|
|
void WrappedOpenGL::Initialise(GLInitParams ¶ms, uint64_t sectionVersion)
|
|
{
|
|
// deliberately want to go through our own wrappers to set up e.g. m_Textures members
|
|
WrappedOpenGL &gl = *this;
|
|
|
|
m_InitParams = params;
|
|
m_SectionVersion = sectionVersion;
|
|
|
|
// as a concession to compatibility, generate a 'fake' VBO to act as VBO 0.
|
|
// consider making it an error/warning for programs to use this?
|
|
gl.glGenVertexArrays(1, &m_FakeVAO);
|
|
gl.glBindVertexArray(m_FakeVAO);
|
|
gl.glBindVertexArray(0);
|
|
|
|
gl.glGenFramebuffers(1, &m_FakeBB_FBO);
|
|
gl.glBindFramebuffer(eGL_FRAMEBUFFER, m_FakeBB_FBO);
|
|
|
|
// we'll add the chunk later when we re-process it.
|
|
ResourceId fboId = GetResourceManager()->GetID(FramebufferRes(GetCtx(), m_FakeBB_FBO));
|
|
AddResource(fboId, ResourceType::SwapchainImage, "");
|
|
GetReplay()->GetResourceDesc(fboId).initialisationChunks.clear();
|
|
GetReplay()->GetResourceDesc(fboId).SetCustomName("Default 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
|
|
RDCERR("Unexpected # colour bits: %d", params.colorBits);
|
|
|
|
GLenum target = eGL_TEXTURE_2D;
|
|
if(params.multiSamples > 1)
|
|
target = eGL_TEXTURE_2D_MULTISAMPLE;
|
|
|
|
gl.glGenTextures(1, &m_FakeBB_Color);
|
|
gl.glBindTexture(target, m_FakeBB_Color);
|
|
|
|
ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color));
|
|
const char *name = "Backbuffer Color";
|
|
|
|
GetResourceManager()->SetName(colorId, name);
|
|
|
|
// we'll add the chunk later when we re-process it.
|
|
AddResource(colorId, ResourceType::SwapchainImage, name);
|
|
GetReplay()->GetResourceDesc(colorId).initialisationChunks.clear();
|
|
GetReplay()->GetResourceDesc(colorId).SetCustomName(name);
|
|
|
|
if(params.multiSamples > 1)
|
|
{
|
|
gl.glTextureStorage2DMultisampleEXT(m_FakeBB_Color, target, params.multiSamples, colfmt,
|
|
params.width, params.height, true);
|
|
}
|
|
else
|
|
{
|
|
gl.glTextureImage2DEXT(m_FakeBB_Color, target, 0, colfmt, params.width, params.height, 0,
|
|
GetBaseFormat(colfmt), GetDataType(colfmt), NULL);
|
|
gl.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0);
|
|
gl.glTexParameteri(target, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
|
|
gl.glTexParameteri(target, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
|
|
gl.glTexParameteri(target, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
|
|
gl.glTexParameteri(target, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
|
|
}
|
|
gl.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, target, m_FakeBB_Color, 0);
|
|
|
|
gl.glViewport(0, 0, params.width, params.height);
|
|
|
|
m_FakeBB_DepthStencil = 0;
|
|
if(params.depthBits > 0 || params.stencilBits > 0)
|
|
{
|
|
gl.glGenTextures(1, &m_FakeBB_DepthStencil);
|
|
gl.glBindTexture(target, m_FakeBB_DepthStencil);
|
|
|
|
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
|
|
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);
|
|
|
|
ResourceId depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_DepthStencil));
|
|
name = stencil ? "Backbuffer Depth-stencil" : "Backbuffer Depth";
|
|
|
|
GetResourceManager()->SetName(depthId, name);
|
|
|
|
// we'll add the chunk later when we re-process it.
|
|
AddResource(depthId, ResourceType::SwapchainImage, name);
|
|
GetReplay()->GetResourceDesc(depthId).initialisationChunks.clear();
|
|
GetReplay()->GetResourceDesc(depthId).SetCustomName(name);
|
|
|
|
if(params.multiSamples > 1)
|
|
{
|
|
gl.glTextureStorage2DMultisampleEXT(m_FakeBB_DepthStencil, target, params.multiSamples,
|
|
depthfmt, params.width, params.height, true);
|
|
}
|
|
else
|
|
{
|
|
gl.glTexParameteri(target, eGL_TEXTURE_MAX_LEVEL, 0);
|
|
gl.glTextureImage2DEXT(m_FakeBB_DepthStencil, target, 0, depthfmt, params.width,
|
|
params.height, 0, GetBaseFormat(depthfmt), GetDataType(depthfmt), NULL);
|
|
}
|
|
|
|
if(stencil)
|
|
gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, m_FakeBB_DepthStencil,
|
|
0);
|
|
else
|
|
gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, m_FakeBB_DepthStencil, 0);
|
|
}
|
|
|
|
// give the backbuffer a default clear color
|
|
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
gl.glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
if(params.depthBits > 0)
|
|
{
|
|
gl.glClearDepthf(1.0f);
|
|
gl.glClear(GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
if(params.stencilBits > 0)
|
|
{
|
|
gl.glClearStencil(0);
|
|
gl.glClear(GL_STENCIL_BUFFER_BIT);
|
|
}
|
|
}
|
|
|
|
std::string WrappedOpenGL::GetChunkName(uint32_t idx)
|
|
{
|
|
if((SystemChunk)idx < SystemChunk::FirstDriverChunk)
|
|
return ToStr((SystemChunk)idx);
|
|
|
|
return ToStr((GLChunk)idx);
|
|
}
|
|
|
|
WrappedOpenGL::~WrappedOpenGL()
|
|
{
|
|
if(m_FakeVAO)
|
|
m_Real.glDeleteVertexArrays(1, &m_FakeVAO);
|
|
if(m_FakeBB_FBO)
|
|
m_Real.glDeleteFramebuffers(1, &m_FakeBB_FBO);
|
|
if(m_FakeBB_Color)
|
|
m_Real.glDeleteTextures(1, &m_FakeBB_Color);
|
|
if(m_FakeBB_DepthStencil)
|
|
m_Real.glDeleteTextures(1, &m_FakeBB_DepthStencil);
|
|
|
|
SAFE_DELETE(m_FrameReader);
|
|
|
|
GetResourceManager()->ReleaseCurrentResource(m_DeviceResourceID);
|
|
GetResourceManager()->ReleaseCurrentResource(m_ContextResourceID);
|
|
|
|
if(m_ContextRecord)
|
|
{
|
|
RDCASSERT(m_ContextRecord->GetRefCount() == 1);
|
|
m_ContextRecord->Delete(GetResourceManager());
|
|
}
|
|
|
|
if(m_DeviceRecord)
|
|
{
|
|
RDCASSERT(m_DeviceRecord->GetRefCount() == 1);
|
|
m_DeviceRecord->Delete(GetResourceManager());
|
|
}
|
|
|
|
m_ResourceManager->Shutdown();
|
|
|
|
SAFE_DELETE(m_ResourceManager);
|
|
|
|
if(RenderDoc::Inst().GetCrashHandler())
|
|
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
|
|
}
|
|
|
|
void *WrappedOpenGL::GetCtx()
|
|
{
|
|
return (void *)m_ActiveContexts[Threading::GetCurrentID()].ctx;
|
|
}
|
|
|
|
WrappedOpenGL::ContextData &WrappedOpenGL::GetCtxData()
|
|
{
|
|
return m_ContextData[GetCtx()];
|
|
}
|
|
|
|
// defined in gl_<platform>_hooks.cpp
|
|
Threading::CriticalSection &GetGLLock();
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Windowing/setup/etc
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void WrappedOpenGL::DeleteContext(void *contextHandle)
|
|
{
|
|
ContextData &ctxdata = m_ContextData[contextHandle];
|
|
|
|
RenderDoc::Inst().RemoveDeviceFrameCapturer(ctxdata.ctx);
|
|
|
|
if(ctxdata.built && ctxdata.ready)
|
|
{
|
|
if(ctxdata.Program)
|
|
m_Real.glDeleteProgram(ctxdata.Program);
|
|
if(ctxdata.GeneralUBO)
|
|
m_Real.glDeleteBuffers(1, &ctxdata.GeneralUBO);
|
|
if(ctxdata.GlyphUBO)
|
|
m_Real.glDeleteBuffers(1, &ctxdata.GlyphUBO);
|
|
if(ctxdata.StringUBO)
|
|
m_Real.glDeleteBuffers(1, &ctxdata.StringUBO);
|
|
if(ctxdata.GlyphTexture)
|
|
m_Real.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);
|
|
|
|
for(auto it = m_LastContexts.begin(); it != m_LastContexts.end(); ++it)
|
|
{
|
|
if(it->ctx == contextHandle)
|
|
{
|
|
m_LastContexts.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_ContextData.erase(contextHandle);
|
|
}
|
|
|
|
void WrappedOpenGL::ContextData::UnassociateWindow(void *wndHandle)
|
|
{
|
|
auto it = windows.find(wndHandle);
|
|
if(it != windows.end())
|
|
{
|
|
windows.erase(wndHandle);
|
|
RenderDoc::Inst().RemoveFrameCapturer(ctx, wndHandle);
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::ContextData::AssociateWindow(WrappedOpenGL *gl, void *wndHandle)
|
|
{
|
|
auto it = windows.find(wndHandle);
|
|
if(it == windows.end())
|
|
RenderDoc::Inst().AddFrameCapturer(ctx, wndHandle, gl);
|
|
|
|
windows[wndHandle] = Timing::GetUnixTimestamp();
|
|
}
|
|
|
|
void WrappedOpenGL::ContextData::CreateDebugData(const GLHookSet &gl)
|
|
{
|
|
// to let us display the overlay on old GL contexts, use as simple a subset of functionality as
|
|
// possible
|
|
// to upload the texture. VAO and shaders are used optionally on modern contexts, otherwise we
|
|
// fall back
|
|
// to immediate mode rendering by hand
|
|
if(gl.glGetIntegerv && gl.glGenTextures && gl.glBindTexture && gl.glTexImage2D && gl.glTexParameteri)
|
|
{
|
|
string ttfstring = GetEmbeddedResource(sourcecodepro_ttf);
|
|
byte *ttfdata = (byte *)ttfstring.c_str();
|
|
|
|
byte *buf = new byte[FONT_TEX_WIDTH * FONT_TEX_HEIGHT];
|
|
|
|
stbtt_BakeFontBitmap(ttfdata, 0, charPixelHeight, buf, FONT_TEX_WIDTH, FONT_TEX_HEIGHT,
|
|
firstChar, numChars, chardata);
|
|
|
|
CharSize = charPixelHeight;
|
|
CharAspect = chardata->xadvance / charPixelHeight;
|
|
|
|
stbtt_fontinfo f = {0};
|
|
stbtt_InitFont(&f, ttfdata, 0);
|
|
|
|
int ascent = 0;
|
|
stbtt_GetFontVMetrics(&f, &ascent, NULL, NULL);
|
|
|
|
float maxheight = float(ascent) * stbtt_ScaleForPixelHeight(&f, charPixelHeight);
|
|
|
|
{
|
|
PixelUnpackState unpack;
|
|
|
|
unpack.Fetch(&gl, false);
|
|
|
|
ResetPixelUnpackState(gl, false, 1);
|
|
|
|
GLuint curtex = 0;
|
|
gl.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint *)&curtex);
|
|
|
|
GLenum texFmt = eGL_R8;
|
|
if(Legacy())
|
|
texFmt = eGL_LUMINANCE;
|
|
|
|
gl.glGenTextures(1, &GlyphTexture);
|
|
gl.glBindTexture(eGL_TEXTURE_2D, GlyphTexture);
|
|
gl.glTexImage2D(eGL_TEXTURE_2D, 0, texFmt, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, 0, eGL_RED,
|
|
eGL_UNSIGNED_BYTE, buf);
|
|
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAX_LEVEL, 0);
|
|
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_LINEAR);
|
|
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_LINEAR);
|
|
|
|
gl.glBindTexture(eGL_TEXTURE_2D, curtex);
|
|
|
|
unpack.Apply(&gl, false);
|
|
}
|
|
|
|
delete[] buf;
|
|
|
|
Vec4f glyphData[2 * (numChars + 1)];
|
|
|
|
for(int i = 0; i < numChars; i++)
|
|
{
|
|
stbtt_bakedchar *b = chardata + i;
|
|
|
|
float x = b->xoff;
|
|
float y = b->yoff + maxheight;
|
|
|
|
glyphData[(i + 1) * 2 + 0] =
|
|
Vec4f(x / b->xadvance, y / charPixelHeight, b->xadvance / float(b->x1 - b->x0),
|
|
charPixelHeight / float(b->y1 - b->y0));
|
|
glyphData[(i + 1) * 2 + 1] = Vec4f(b->x0, b->y0, b->x1, b->y1);
|
|
}
|
|
|
|
if(Modern() && gl.glGenVertexArrays && gl.glBindVertexArray)
|
|
{
|
|
GLuint curvao = 0;
|
|
gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&curvao);
|
|
|
|
gl.glGenVertexArrays(1, &DummyVAO);
|
|
gl.glBindVertexArray(DummyVAO);
|
|
|
|
gl.glBindVertexArray(curvao);
|
|
}
|
|
|
|
if(Modern() && gl.glGenBuffers && gl.glBufferData && gl.glBindBuffer)
|
|
{
|
|
GLuint curubo = 0;
|
|
gl.glGetIntegerv(eGL_UNIFORM_BUFFER_BINDING, (GLint *)&curubo);
|
|
|
|
gl.glGenBuffers(1, &GlyphUBO);
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, GlyphUBO);
|
|
gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(glyphData), glyphData, eGL_STATIC_DRAW);
|
|
|
|
gl.glGenBuffers(1, &GeneralUBO);
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, GeneralUBO);
|
|
gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(FontUBOData), NULL, eGL_DYNAMIC_DRAW);
|
|
|
|
gl.glGenBuffers(1, &StringUBO);
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, StringUBO);
|
|
gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(uint32_t) * 4 * FONT_MAX_CHARS, NULL,
|
|
eGL_DYNAMIC_DRAW);
|
|
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, curubo);
|
|
}
|
|
|
|
if(Modern() && gl.glCreateShader && gl.glShaderSource && gl.glCompileShader &&
|
|
gl.glGetShaderiv && gl.glGetShaderInfoLog && gl.glDeleteShader && gl.glCreateProgram &&
|
|
gl.glAttachShader && gl.glLinkProgram && gl.glGetProgramiv && gl.glGetProgramInfoLog)
|
|
{
|
|
vector<string> vs;
|
|
vector<string> fs;
|
|
|
|
ShaderType shaderType;
|
|
int glslVersion;
|
|
string fragDefines;
|
|
|
|
if(IsGLES)
|
|
{
|
|
shaderType = eShaderGLSLES;
|
|
glslVersion = 310;
|
|
fragDefines = "";
|
|
}
|
|
else
|
|
{
|
|
shaderType = eShaderGLSL;
|
|
glslVersion = 150;
|
|
fragDefines =
|
|
"#extension GL_ARB_shading_language_420pack : require\n"
|
|
"#extension GL_ARB_separate_shader_objects : require\n"
|
|
"#extension GL_ARB_explicit_attrib_location : require\n";
|
|
}
|
|
|
|
GenerateGLSLShader(vs, shaderType, "", GetEmbeddedResource(glsl_text_vert), glslVersion);
|
|
GenerateGLSLShader(fs, shaderType, fragDefines, GetEmbeddedResource(glsl_text_frag),
|
|
glslVersion);
|
|
|
|
vector<const char *> vsc;
|
|
vsc.reserve(vs.size());
|
|
vector<const char *> fsc;
|
|
fsc.reserve(fs.size());
|
|
|
|
for(size_t i = 0; i < vs.size(); i++)
|
|
vsc.push_back(vs[i].c_str());
|
|
|
|
for(size_t i = 0; i < fs.size(); i++)
|
|
fsc.push_back(fs[i].c_str());
|
|
|
|
GLuint vert = gl.glCreateShader(eGL_VERTEX_SHADER);
|
|
GLuint frag = gl.glCreateShader(eGL_FRAGMENT_SHADER);
|
|
|
|
gl.glShaderSource(vert, (GLsizei)vs.size(), &vsc[0], NULL);
|
|
gl.glShaderSource(frag, (GLsizei)fs.size(), &fsc[0], NULL);
|
|
|
|
gl.glCompileShader(vert);
|
|
gl.glCompileShader(frag);
|
|
|
|
char buffer[1024] = {0};
|
|
GLint status = 0;
|
|
|
|
gl.glGetShaderiv(vert, eGL_COMPILE_STATUS, &status);
|
|
if(status == 0)
|
|
{
|
|
gl.glGetShaderInfoLog(vert, 1024, NULL, buffer);
|
|
RDCERR("Shader error: %s", buffer);
|
|
}
|
|
|
|
gl.glGetShaderiv(frag, eGL_COMPILE_STATUS, &status);
|
|
if(status == 0)
|
|
{
|
|
gl.glGetShaderInfoLog(frag, 1024, NULL, buffer);
|
|
RDCERR("Shader error: %s", buffer);
|
|
}
|
|
|
|
Program = gl.glCreateProgram();
|
|
|
|
gl.glAttachShader(Program, vert);
|
|
gl.glAttachShader(Program, frag);
|
|
|
|
gl.glLinkProgram(Program);
|
|
|
|
gl.glGetProgramiv(Program, eGL_LINK_STATUS, &status);
|
|
if(status == 0)
|
|
{
|
|
gl.glGetProgramInfoLog(Program, 1024, NULL, buffer);
|
|
RDCERR("Link error: %s", buffer);
|
|
}
|
|
|
|
gl.glDeleteShader(vert);
|
|
gl.glDeleteShader(frag);
|
|
}
|
|
|
|
ready = true;
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext,
|
|
GLInitParams initParams, bool core, bool attribsCreate)
|
|
{
|
|
// TODO: support multiple GL contexts more explicitly
|
|
m_InitParams = initParams;
|
|
|
|
ContextData &ctxdata = m_ContextData[winData.ctx];
|
|
ctxdata.ctx = winData.ctx;
|
|
ctxdata.isCore = core;
|
|
ctxdata.attribsCreate = attribsCreate;
|
|
|
|
RenderDoc::Inst().AddDeviceFrameCapturer(ctxdata.ctx, this);
|
|
}
|
|
|
|
void WrappedOpenGL::RegisterContext(GLWindowingData winData, void *shareContext, bool core,
|
|
bool attribsCreate)
|
|
{
|
|
ContextData &ctxdata = m_ContextData[winData.ctx];
|
|
ctxdata.ctx = winData.ctx;
|
|
ctxdata.isCore = core;
|
|
ctxdata.attribsCreate = attribsCreate;
|
|
}
|
|
|
|
void WrappedOpenGL::ActivateContext(GLWindowingData winData)
|
|
{
|
|
m_ActiveContexts[Threading::GetCurrentID()] = winData;
|
|
if(winData.ctx)
|
|
{
|
|
for(auto it = m_LastContexts.begin(); it != m_LastContexts.end(); ++it)
|
|
{
|
|
if(it->ctx == winData.ctx)
|
|
{
|
|
m_LastContexts.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_LastContexts.push_back(winData);
|
|
|
|
if(m_LastContexts.size() > 10)
|
|
m_LastContexts.erase(m_LastContexts.begin());
|
|
}
|
|
|
|
// TODO: support multiple GL contexts more explicitly
|
|
Keyboard::AddInputWindow((void *)winData.wnd);
|
|
|
|
if(winData.ctx)
|
|
{
|
|
// if we're capturing, we need to serialise out the changed state vector
|
|
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
|
|
QueuedInitialStateFetch fetch;
|
|
fetch.res.Context = winData.ctx;
|
|
auto it = std::lower_bound(m_QueuedInitialFetches.begin(), m_QueuedInitialFetches.end(), fetch);
|
|
for(; it != m_QueuedInitialFetches.end();)
|
|
{
|
|
GetResourceManager()->Prepare_InitialState(it->res, it->blob);
|
|
it = m_QueuedInitialFetches.erase(it);
|
|
}
|
|
|
|
USE_SCRATCH_SERIALISER();
|
|
SCOPED_SERIALISE_CHUNK(GLChunk::MakeContextCurrent);
|
|
Serialise_BeginCaptureFrame(ser);
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
ContextData &ctxdata = m_ContextData[winData.ctx];
|
|
|
|
if(!ctxdata.built)
|
|
{
|
|
ctxdata.built = true;
|
|
|
|
const vector<string> &globalExts = IsGLES ? m_GLESExtensions : m_GLExtensions;
|
|
const GLHookSet &gl = m_Real;
|
|
|
|
if(HasExt[KHR_debug] && gl.glDebugMessageCallback &&
|
|
RenderDoc::Inst().GetCaptureOptions().APIValidation)
|
|
{
|
|
gl.glDebugMessageCallback(&DebugSnoopStatic, this);
|
|
gl.glEnable(eGL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
}
|
|
|
|
vector<string> implExts;
|
|
|
|
if(gl.glGetIntegerv && gl.glGetStringi)
|
|
{
|
|
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)
|
|
{
|
|
string 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 string &a = implExts[i];
|
|
const string &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");
|
|
|
|
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(gl, m_Platform, winData);
|
|
}
|
|
}
|
|
|
|
if(IsCaptureMode(m_State))
|
|
{
|
|
PUSH_CURRENT_CHUNK;
|
|
GLuint prevArrayBuffer = 0;
|
|
glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint *)&prevArrayBuffer);
|
|
|
|
// 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);
|
|
}
|
|
|
|
gl_CurChunk = GLChunk::glBindBuffer;
|
|
glBindBuffer(eGL_ARRAY_BUFFER, prevArrayBuffer);
|
|
|
|
gl_CurChunk = GLChunk::glGenBuffers;
|
|
glGenBuffers(1, &ctxdata.m_ClientMemoryIBO);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::WindowSize(void *windowHandle, uint32_t w, uint32_t h)
|
|
{
|
|
// TODO: support multiple window handles
|
|
m_InitParams.width = w;
|
|
m_InitParams.height = h;
|
|
}
|
|
|
|
// TODO this could be a general class for use elsewhere (ie. code that wants
|
|
// to push and pop would set state through the class, which records dirty bits
|
|
// and then restores).
|
|
struct RenderTextState
|
|
{
|
|
bool enableBits[8];
|
|
GLenum ClipOrigin, ClipDepth;
|
|
GLenum EquationRGB, EquationAlpha;
|
|
GLenum SourceRGB, SourceAlpha;
|
|
GLenum DestinationRGB, DestinationAlpha;
|
|
GLenum PolygonMode;
|
|
GLfloat Viewportf[4];
|
|
GLint Viewport[4];
|
|
GLenum ActiveTexture;
|
|
GLuint tex0;
|
|
GLuint ubo[3];
|
|
GLuint prog;
|
|
GLuint pipe;
|
|
GLuint VAO;
|
|
GLuint drawFBO;
|
|
|
|
// if this context wasn't created with CreateContextAttribs we
|
|
// do an immediate mode render, so fewer states are pushed/popped.
|
|
// note we don't assume a 1.0 context since that would be painful to
|
|
// handle. Instead we just skip bits of state we're not going to mess
|
|
// with. In some cases this might cause problems e.g. we don't use
|
|
// indexed enable states for blend and scissor test because we're
|
|
// assuming there's no separate blending.
|
|
//
|
|
// In the end, this is just a best-effort to keep going without
|
|
// crashing. Old GL versions aren't supported.
|
|
void Push(const GLHookSet &gl, bool modern)
|
|
{
|
|
enableBits[0] = gl.glIsEnabled(eGL_DEPTH_TEST) != 0;
|
|
enableBits[1] = gl.glIsEnabled(eGL_STENCIL_TEST) != 0;
|
|
enableBits[2] = gl.glIsEnabled(eGL_CULL_FACE) != 0;
|
|
if(modern)
|
|
{
|
|
if(!IsGLES)
|
|
enableBits[3] = gl.glIsEnabled(eGL_DEPTH_CLAMP) != 0;
|
|
|
|
if(HasExt[ARB_draw_buffers_blend])
|
|
enableBits[4] = gl.glIsEnabledi(eGL_BLEND, 0) != 0;
|
|
else
|
|
enableBits[4] = gl.glIsEnabled(eGL_BLEND) != 0;
|
|
|
|
if(HasExt[ARB_viewport_array])
|
|
enableBits[5] = gl.glIsEnabledi(eGL_SCISSOR_TEST, 0) != 0;
|
|
else
|
|
enableBits[5] = gl.glIsEnabled(eGL_SCISSOR_TEST) != 0;
|
|
}
|
|
else
|
|
{
|
|
enableBits[3] = gl.glIsEnabled(eGL_BLEND) != 0;
|
|
enableBits[4] = gl.glIsEnabled(eGL_SCISSOR_TEST) != 0;
|
|
enableBits[5] = gl.glIsEnabled(eGL_TEXTURE_2D) != 0;
|
|
enableBits[6] = gl.glIsEnabled(eGL_LIGHTING) != 0;
|
|
enableBits[7] = gl.glIsEnabled(eGL_ALPHA_TEST) != 0;
|
|
}
|
|
|
|
if(modern && HasExt[ARB_clip_control])
|
|
{
|
|
gl.glGetIntegerv(eGL_CLIP_ORIGIN, (GLint *)&ClipOrigin);
|
|
gl.glGetIntegerv(eGL_CLIP_DEPTH_MODE, (GLint *)&ClipDepth);
|
|
}
|
|
else
|
|
{
|
|
ClipOrigin = eGL_LOWER_LEFT;
|
|
ClipDepth = eGL_NEGATIVE_ONE_TO_ONE;
|
|
}
|
|
|
|
if(modern && HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
gl.glGetIntegeri_v(eGL_BLEND_EQUATION_RGB, 0, (GLint *)&EquationRGB);
|
|
gl.glGetIntegeri_v(eGL_BLEND_EQUATION_ALPHA, 0, (GLint *)&EquationAlpha);
|
|
|
|
gl.glGetIntegeri_v(eGL_BLEND_SRC_RGB, 0, (GLint *)&SourceRGB);
|
|
gl.glGetIntegeri_v(eGL_BLEND_SRC_ALPHA, 0, (GLint *)&SourceAlpha);
|
|
|
|
gl.glGetIntegeri_v(eGL_BLEND_DST_RGB, 0, (GLint *)&DestinationRGB);
|
|
gl.glGetIntegeri_v(eGL_BLEND_DST_ALPHA, 0, (GLint *)&DestinationAlpha);
|
|
}
|
|
else
|
|
{
|
|
gl.glGetIntegerv(eGL_BLEND_EQUATION_RGB, (GLint *)&EquationRGB);
|
|
gl.glGetIntegerv(eGL_BLEND_EQUATION_ALPHA, (GLint *)&EquationAlpha);
|
|
|
|
gl.glGetIntegerv(eGL_BLEND_SRC_RGB, (GLint *)&SourceRGB);
|
|
gl.glGetIntegerv(eGL_BLEND_SRC_ALPHA, (GLint *)&SourceAlpha);
|
|
|
|
gl.glGetIntegerv(eGL_BLEND_DST_RGB, (GLint *)&DestinationRGB);
|
|
gl.glGetIntegerv(eGL_BLEND_DST_ALPHA, (GLint *)&DestinationAlpha);
|
|
}
|
|
|
|
if(!VendorCheck[VendorCheck_AMD_polygon_mode_query] && !IsGLES)
|
|
{
|
|
GLenum dummy[2] = {eGL_FILL, eGL_FILL};
|
|
// docs suggest this is enumeration[2] even though polygon mode can't be set independently for
|
|
// front
|
|
// and back faces.
|
|
gl.glGetIntegerv(eGL_POLYGON_MODE, (GLint *)&dummy);
|
|
PolygonMode = dummy[0];
|
|
}
|
|
else
|
|
{
|
|
PolygonMode = eGL_FILL;
|
|
}
|
|
|
|
if(modern && HasExt[ARB_viewport_array])
|
|
gl.glGetFloati_v(eGL_VIEWPORT, 0, &Viewportf[0]);
|
|
else
|
|
gl.glGetIntegerv(eGL_VIEWPORT, &Viewport[0]);
|
|
|
|
gl.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&ActiveTexture);
|
|
gl.glActiveTexture(eGL_TEXTURE0);
|
|
gl.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint *)&tex0);
|
|
|
|
// we get the current program but only try to restore it if it's non-0
|
|
prog = 0;
|
|
if(modern)
|
|
gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog);
|
|
|
|
drawFBO = 0;
|
|
gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&drawFBO);
|
|
|
|
// since we will use the fixed function pipeline, also need to check for
|
|
// program pipeline bindings (if we weren't, our program would override)
|
|
pipe = 0;
|
|
if(modern && HasExt[ARB_separate_shader_objects])
|
|
gl.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe);
|
|
|
|
if(modern)
|
|
{
|
|
gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 0, (GLint *)&ubo[0]);
|
|
gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 1, (GLint *)&ubo[1]);
|
|
gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 2, (GLint *)&ubo[2]);
|
|
|
|
gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO);
|
|
}
|
|
}
|
|
|
|
void Pop(const GLHookSet &gl, bool modern)
|
|
{
|
|
if(enableBits[0])
|
|
gl.glEnable(eGL_DEPTH_TEST);
|
|
else
|
|
gl.glDisable(eGL_DEPTH_TEST);
|
|
if(enableBits[1])
|
|
gl.glEnable(eGL_STENCIL_TEST);
|
|
else
|
|
gl.glDisable(eGL_STENCIL_TEST);
|
|
if(enableBits[2])
|
|
gl.glEnable(eGL_CULL_FACE);
|
|
else
|
|
gl.glDisable(eGL_CULL_FACE);
|
|
|
|
if(modern)
|
|
{
|
|
if(!IsGLES)
|
|
{
|
|
if(enableBits[3])
|
|
gl.glEnable(eGL_DEPTH_CLAMP);
|
|
else
|
|
gl.glDisable(eGL_DEPTH_CLAMP);
|
|
}
|
|
|
|
if(HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
if(enableBits[4])
|
|
gl.glEnablei(eGL_BLEND, 0);
|
|
else
|
|
gl.glDisablei(eGL_BLEND, 0);
|
|
}
|
|
else
|
|
{
|
|
if(enableBits[4])
|
|
gl.glEnable(eGL_BLEND);
|
|
else
|
|
gl.glDisable(eGL_BLEND);
|
|
}
|
|
|
|
if(HasExt[ARB_viewport_array])
|
|
{
|
|
if(enableBits[5])
|
|
gl.glEnablei(eGL_SCISSOR_TEST, 0);
|
|
else
|
|
gl.glDisablei(eGL_SCISSOR_TEST, 0);
|
|
}
|
|
else
|
|
{
|
|
if(enableBits[5])
|
|
gl.glEnable(eGL_SCISSOR_TEST);
|
|
else
|
|
gl.glDisable(eGL_SCISSOR_TEST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(enableBits[3])
|
|
gl.glEnable(eGL_BLEND);
|
|
else
|
|
gl.glDisable(eGL_BLEND);
|
|
if(enableBits[4])
|
|
gl.glEnable(eGL_SCISSOR_TEST);
|
|
else
|
|
gl.glDisable(eGL_SCISSOR_TEST);
|
|
if(enableBits[5])
|
|
gl.glEnable(eGL_TEXTURE_2D);
|
|
else
|
|
gl.glDisable(eGL_TEXTURE_2D);
|
|
if(enableBits[6])
|
|
gl.glEnable(eGL_LIGHTING);
|
|
else
|
|
gl.glDisable(eGL_LIGHTING);
|
|
if(enableBits[7])
|
|
gl.glEnable(eGL_ALPHA_TEST);
|
|
else
|
|
gl.glDisable(eGL_ALPHA_TEST);
|
|
}
|
|
|
|
if(modern && gl.glClipControl && HasExt[ARB_clip_control])
|
|
gl.glClipControl(ClipOrigin, ClipDepth);
|
|
|
|
if(modern && HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
gl.glBlendFuncSeparatei(0, SourceRGB, DestinationRGB, SourceAlpha, DestinationAlpha);
|
|
gl.glBlendEquationSeparatei(0, EquationRGB, EquationAlpha);
|
|
}
|
|
else
|
|
{
|
|
gl.glBlendFuncSeparate(SourceRGB, DestinationRGB, SourceAlpha, DestinationAlpha);
|
|
gl.glBlendEquationSeparate(EquationRGB, EquationAlpha);
|
|
}
|
|
|
|
if(!IsGLES)
|
|
gl.glPolygonMode(eGL_FRONT_AND_BACK, PolygonMode);
|
|
|
|
if(modern && HasExt[ARB_viewport_array])
|
|
gl.glViewportIndexedf(0, Viewportf[0], Viewportf[1], Viewportf[2], Viewportf[3]);
|
|
else
|
|
gl.glViewport(Viewport[0], Viewport[1], (GLsizei)Viewport[2], (GLsizei)Viewport[3]);
|
|
|
|
gl.glActiveTexture(eGL_TEXTURE0);
|
|
gl.glBindTexture(eGL_TEXTURE_2D, tex0);
|
|
gl.glActiveTexture(ActiveTexture);
|
|
|
|
if(drawFBO != 0 && gl.glBindFramebuffer)
|
|
gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, drawFBO);
|
|
|
|
if(modern)
|
|
{
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ubo[0]);
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ubo[1]);
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ubo[2]);
|
|
|
|
gl.glUseProgram(prog);
|
|
|
|
gl.glBindVertexArray(VAO);
|
|
}
|
|
else
|
|
{
|
|
// only restore these if there was a setting and the function pointer exists
|
|
if(gl.glUseProgram && prog != 0)
|
|
gl.glUseProgram(prog);
|
|
if(gl.glBindProgramPipeline && pipe != 0)
|
|
gl.glBindProgramPipeline(pipe);
|
|
}
|
|
}
|
|
};
|
|
|
|
void WrappedOpenGL::RenderOverlayText(float x, float y, const char *fmt, ...)
|
|
{
|
|
static char tmpBuf[4096];
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
StringFormat::vsnprintf(tmpBuf, 4095, fmt, args);
|
|
tmpBuf[4095] = '\0';
|
|
va_end(args);
|
|
|
|
RenderOverlayStr(x, y, tmpBuf);
|
|
}
|
|
|
|
void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text)
|
|
{
|
|
if(char *t = strchr((char *)text, '\n'))
|
|
{
|
|
*t = 0;
|
|
RenderOverlayStr(x, y, text);
|
|
RenderOverlayStr(x, y + 1.0f, t + 1);
|
|
*t = '\n';
|
|
return;
|
|
}
|
|
|
|
if(strlen(text) == 0)
|
|
return;
|
|
|
|
const GLHookSet &gl = m_Real;
|
|
|
|
RDCASSERT(strlen(text) < (size_t)FONT_MAX_CHARS);
|
|
|
|
ContextData &ctxdata = m_ContextData[GetCtx()];
|
|
|
|
if(!ctxdata.built || !ctxdata.ready)
|
|
return;
|
|
|
|
// if it's reasonably modern context, assume we can use buffers and UBOs
|
|
if(ctxdata.Modern())
|
|
{
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, ctxdata.GeneralUBO);
|
|
|
|
FontUBOData *ubo = (FontUBOData *)gl.glMapBufferRange(
|
|
eGL_UNIFORM_BUFFER, 0, sizeof(FontUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
|
ubo->TextPosition.x = x;
|
|
ubo->TextPosition.y = y;
|
|
|
|
ubo->FontScreenAspect.x = 1.0f / float(m_InitParams.width);
|
|
ubo->FontScreenAspect.y = 1.0f / float(m_InitParams.height);
|
|
|
|
ubo->TextSize = ctxdata.CharSize;
|
|
ubo->FontScreenAspect.x *= ctxdata.CharAspect;
|
|
|
|
ubo->CharacterSize.x = 1.0f / float(FONT_TEX_WIDTH);
|
|
ubo->CharacterSize.y = 1.0f / float(FONT_TEX_HEIGHT);
|
|
|
|
gl.glUnmapBuffer(eGL_UNIFORM_BUFFER);
|
|
|
|
size_t len = strlen(text);
|
|
|
|
if((int)len > FONT_MAX_CHARS)
|
|
{
|
|
static bool printedWarning = false;
|
|
|
|
// this could be called once a frame, don't want to spam the log
|
|
if(!printedWarning)
|
|
{
|
|
printedWarning = true;
|
|
RDCWARN("log string '%s' is too long", text, (int)len);
|
|
}
|
|
|
|
len = FONT_MAX_CHARS;
|
|
}
|
|
|
|
gl.glBindBuffer(eGL_UNIFORM_BUFFER, ctxdata.StringUBO);
|
|
uint32_t *texs =
|
|
(uint32_t *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, len * 4 * sizeof(uint32_t),
|
|
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
|
|
|
if(texs)
|
|
{
|
|
for(size_t i = 0; i < len; i++)
|
|
{
|
|
texs[i * 4 + 0] = text[i] - ' ';
|
|
texs[i * 4 + 1] = text[i] - ' ';
|
|
texs[i * 4 + 2] = text[i] - ' ';
|
|
texs[i * 4 + 3] = text[i] - ' ';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static bool printedWarning = false;
|
|
|
|
// this could be called once a frame, don't want to spam the log
|
|
if(!printedWarning)
|
|
{
|
|
printedWarning = true;
|
|
RDCWARN("failed to map %d characters for '%s' (%d)", (int)len, text, ctxdata.StringUBO);
|
|
}
|
|
}
|
|
|
|
gl.glUnmapBuffer(eGL_UNIFORM_BUFFER);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Make sure if you change any other state in here, that you also update the push
|
|
// and pop functions above (RenderTextState)
|
|
|
|
// set blend state
|
|
if(HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
gl.glEnablei(eGL_BLEND, 0);
|
|
gl.glBlendFuncSeparatei(0, eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA, eGL_SRC_ALPHA,
|
|
eGL_SRC_ALPHA);
|
|
gl.glBlendEquationSeparatei(0, eGL_FUNC_ADD, eGL_FUNC_ADD);
|
|
}
|
|
else
|
|
{
|
|
gl.glEnable(eGL_BLEND);
|
|
gl.glBlendFuncSeparate(eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA, eGL_SRC_ALPHA, eGL_SRC_ALPHA);
|
|
gl.glBlendEquationSeparate(eGL_FUNC_ADD, eGL_FUNC_ADD);
|
|
}
|
|
|
|
// set depth & stencil
|
|
gl.glDisable(eGL_DEPTH_TEST);
|
|
if(!IsGLES)
|
|
gl.glDisable(eGL_DEPTH_CLAMP);
|
|
gl.glDisable(eGL_STENCIL_TEST);
|
|
gl.glDisable(eGL_CULL_FACE);
|
|
|
|
gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
// set viewport & scissor
|
|
if(HasExt[ARB_viewport_array])
|
|
{
|
|
gl.glViewportIndexedf(0, 0.0f, 0.0f, (float)m_InitParams.width, (float)m_InitParams.height);
|
|
gl.glDisablei(eGL_SCISSOR_TEST, 0);
|
|
}
|
|
else
|
|
{
|
|
gl.glViewport(0, 0, m_InitParams.width, m_InitParams.height);
|
|
gl.glDisable(eGL_SCISSOR_TEST);
|
|
}
|
|
|
|
if(!IsGLES)
|
|
gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL);
|
|
|
|
if(gl.glClipControl && HasExt[ARB_clip_control])
|
|
gl.glClipControl(eGL_LOWER_LEFT, eGL_NEGATIVE_ONE_TO_ONE);
|
|
|
|
// bind UBOs
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.GeneralUBO);
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ctxdata.GlyphUBO);
|
|
gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ctxdata.StringUBO);
|
|
|
|
// bind empty VAO just for valid rendering
|
|
gl.glBindVertexArray(ctxdata.DummyVAO);
|
|
|
|
// bind textures
|
|
gl.glActiveTexture(eGL_TEXTURE0);
|
|
gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture);
|
|
|
|
// bind program
|
|
gl.glUseProgram(ctxdata.Program);
|
|
|
|
// draw string
|
|
gl.glDrawArrays(eGL_TRIANGLES, 0, 6 * (GLsizei)len);
|
|
}
|
|
else
|
|
{
|
|
// if it wasn't created in modern fashion with createattribs, assume the worst
|
|
// and draw with immediate mode (since it's impossible that the context is core
|
|
// profile, this will always work)
|
|
//
|
|
// This isn't perfect since without a lot of fiddling we'd need to check if e.g.
|
|
// indexed blending should be used or not. Since we're not too worried about
|
|
// working in this situation, just doing something reasonable, we just assume
|
|
// roughly ~2.0 functionality
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Make sure if you change any other state in here, that you also update the push
|
|
// and pop functions above (RenderTextState)
|
|
|
|
// disable blending and some old-style fixed function features
|
|
gl.glDisable(eGL_BLEND);
|
|
gl.glDisable(eGL_LIGHTING);
|
|
gl.glDisable(eGL_ALPHA_TEST);
|
|
|
|
// set depth & stencil
|
|
gl.glDisable(eGL_DEPTH_TEST);
|
|
gl.glDisable(eGL_STENCIL_TEST);
|
|
gl.glDisable(eGL_CULL_FACE);
|
|
|
|
// set viewport & scissor
|
|
gl.glViewport(0, 0, (GLsizei)m_InitParams.width, (GLsizei)m_InitParams.height);
|
|
gl.glDisable(eGL_SCISSOR_TEST);
|
|
if(!IsGLES)
|
|
gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL);
|
|
|
|
// bind textures
|
|
gl.glActiveTexture(eGL_TEXTURE0);
|
|
gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture);
|
|
gl.glEnable(eGL_TEXTURE_2D);
|
|
|
|
if(gl.glBindFramebuffer)
|
|
gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
// just in case, try to disable the programmable pipeline
|
|
if(gl.glUseProgram)
|
|
gl.glUseProgram(0);
|
|
if(gl.glBindProgramPipeline)
|
|
gl.glBindProgramPipeline(0);
|
|
|
|
// draw string (based on sample code from stb_truetype.h)
|
|
vector<Vec4f> vertices;
|
|
{
|
|
y += 1.0f;
|
|
y *= charPixelHeight;
|
|
|
|
float startx = x;
|
|
float starty = y;
|
|
|
|
float maxx = x, minx = x;
|
|
float maxy = y, miny = y - charPixelHeight;
|
|
|
|
stbtt_aligned_quad q;
|
|
|
|
const char *prepass = text;
|
|
while(*prepass)
|
|
{
|
|
char c = *prepass;
|
|
if(c >= firstChar && c <= lastChar)
|
|
{
|
|
stbtt_GetBakedQuad(chardata, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, c - firstChar, &x, &y, &q, 1);
|
|
|
|
maxx = RDCMAX(maxx, RDCMAX(q.x0, q.x1));
|
|
maxy = RDCMAX(maxy, RDCMAX(q.y0, q.y1));
|
|
|
|
minx = RDCMIN(minx, RDCMIN(q.x0, q.x1));
|
|
miny = RDCMIN(miny, RDCMIN(q.y0, q.y1));
|
|
}
|
|
else
|
|
{
|
|
x += chardata[0].xadvance;
|
|
}
|
|
prepass++;
|
|
}
|
|
|
|
x = startx;
|
|
y = starty;
|
|
|
|
// draw black bar behind text
|
|
|
|
vertices.push_back(Vec4f(minx, maxy, 0.0f, 0.0f));
|
|
vertices.push_back(Vec4f(maxx, maxy, 0.0f, 0.0f));
|
|
vertices.push_back(Vec4f(maxx, miny, 0.0f, 0.0f));
|
|
vertices.push_back(Vec4f(minx, miny, 0.0f, 0.0f));
|
|
|
|
while(*text)
|
|
{
|
|
char c = *text;
|
|
if(c >= firstChar && c <= lastChar)
|
|
{
|
|
stbtt_GetBakedQuad(chardata, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, c - firstChar, &x, &y, &q, 1);
|
|
|
|
vertices.push_back(Vec4f(q.x0, q.y0, q.s0, q.t0));
|
|
vertices.push_back(Vec4f(q.x1, q.y0, q.s1, q.t0));
|
|
vertices.push_back(Vec4f(q.x1, q.y1, q.s1, q.t1));
|
|
vertices.push_back(Vec4f(q.x0, q.y1, q.s0, q.t1));
|
|
|
|
maxx = RDCMAX(maxx, RDCMAX(q.x0, q.x1));
|
|
maxy = RDCMAX(maxy, RDCMAX(q.y0, q.y1));
|
|
}
|
|
else
|
|
{
|
|
x += chardata[0].xadvance;
|
|
}
|
|
++text;
|
|
}
|
|
}
|
|
m_Platform.DrawQuads((float)m_InitParams.width, (float)m_InitParams.height, vertices);
|
|
}
|
|
}
|
|
|
|
struct ReplacementSearch
|
|
{
|
|
bool operator()(const pair<ResourceId, Replacement> &a, ResourceId b) { return a.first < b; }
|
|
};
|
|
|
|
void WrappedOpenGL::ReplaceResource(ResourceId from, ResourceId to)
|
|
{
|
|
RemoveReplacement(from);
|
|
|
|
if(GetResourceManager()->HasLiveResource(from))
|
|
{
|
|
GLResource resource = GetResourceManager()->GetLiveResource(to);
|
|
ResourceId livefrom = GetResourceManager()->GetLiveID(from);
|
|
|
|
if(resource.Namespace == eResShader)
|
|
{
|
|
// need to replace all programs that use this shader
|
|
for(auto it = m_Programs.begin(); it != m_Programs.end(); ++it)
|
|
{
|
|
ResourceId progsrcid = it->first;
|
|
ProgramData &progdata = it->second;
|
|
|
|
// see if the shader is used
|
|
for(int i = 0; i < 6; i++)
|
|
{
|
|
if(progdata.stageShaders[i] == livefrom)
|
|
{
|
|
GLuint progsrc = GetResourceManager()->GetCurrentResource(progsrcid).name;
|
|
|
|
// make a new program
|
|
GLuint progdst = glCreateProgram();
|
|
|
|
ResourceId progdstid = GetResourceManager()->GetID(ProgramRes(GetCtx(), progdst));
|
|
|
|
// attach all but the i'th shader
|
|
for(int j = 0; j < 6; j++)
|
|
if(i != j && progdata.stageShaders[j] != ResourceId())
|
|
glAttachShader(
|
|
progdst, GetResourceManager()->GetCurrentResource(progdata.stageShaders[j]).name);
|
|
|
|
// attach the new shader
|
|
glAttachShader(progdst, resource.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(m_Real, progsrc, progdst, &m_Shaders[vs].reflection);
|
|
|
|
if(fs != ResourceId())
|
|
CopyProgramFragDataBindings(m_Real, 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
|
|
{
|
|
// copy uniforms
|
|
CopyProgramUniforms(m_Real, progsrc, progdst);
|
|
|
|
ResourceId origsrcid = GetResourceManager()->GetOriginalID(progsrcid);
|
|
|
|
// recursively call to replaceresource (different type - these are programs)
|
|
ReplaceResource(origsrcid, progdstid);
|
|
|
|
// insert into m_DependentReplacements
|
|
auto insertPos =
|
|
std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(),
|
|
from, ReplacementSearch());
|
|
m_DependentReplacements.insert(
|
|
insertPos,
|
|
std::make_pair(from, Replacement(origsrcid, ProgramRes(GetCtx(), progdst))));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(resource.Namespace == eResProgram)
|
|
{
|
|
// need to replace all pipelines that use this program
|
|
for(auto it = m_Pipelines.begin(); it != m_Pipelines.end(); ++it)
|
|
{
|
|
ResourceId pipesrcid = it->first;
|
|
PipelineData &pipedata = it->second;
|
|
|
|
// see if the program is used
|
|
for(int i = 0; i < 6; i++)
|
|
{
|
|
if(pipedata.stagePrograms[i] == livefrom)
|
|
{
|
|
// make a new pipeline
|
|
GLuint pipedst = 0;
|
|
glGenProgramPipelines(1, &pipedst);
|
|
|
|
ResourceId pipedstid = GetResourceManager()->GetID(ProgramPipeRes(GetCtx(), pipedst));
|
|
|
|
// attach all but the i'th program
|
|
for(int j = 0; j < 6; j++)
|
|
{
|
|
if(i != j && pipedata.stagePrograms[j] != ResourceId())
|
|
{
|
|
// if this stage was provided by the program we're replacing, use that instead
|
|
if(pipedata.stagePrograms[i] == pipedata.stagePrograms[j])
|
|
glUseProgramStages(pipedst, ShaderBit(j), resource.name);
|
|
else
|
|
glUseProgramStages(
|
|
pipedst, ShaderBit(j),
|
|
GetResourceManager()->GetCurrentResource(pipedata.stagePrograms[j]).name);
|
|
}
|
|
}
|
|
|
|
// attach the new program in our stage
|
|
glUseProgramStages(pipedst, ShaderBit(i), resource.name);
|
|
|
|
ResourceId origsrcid = GetResourceManager()->GetOriginalID(pipesrcid);
|
|
|
|
// recursively call to replaceresource (different type - these are programs)
|
|
ReplaceResource(origsrcid, pipedstid);
|
|
|
|
// insert into m_DependentReplacements
|
|
auto insertPos =
|
|
std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(),
|
|
from, ReplacementSearch());
|
|
m_DependentReplacements.insert(
|
|
insertPos,
|
|
std::make_pair(from, Replacement(origsrcid, ProgramPipeRes(GetCtx(), pipedst))));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// do actual replacement
|
|
GLResource fromresource = GetResourceManager()->GetLiveResource(from);
|
|
|
|
// if they're the same type it's easy, but it could be we want to replace a shader
|
|
// inside a program which never had a shader (ie. glCreateShaderProgramv)
|
|
if(fromresource.Namespace == resource.Namespace)
|
|
{
|
|
GetResourceManager()->ReplaceResource(from, to);
|
|
}
|
|
else if(fromresource.Namespace == eResProgram && resource.Namespace == eResShader)
|
|
{
|
|
// if we want to replace a program with a shader, assume it's just a program with only one
|
|
// shader attached. This will have been handled above in the "programs dependent on this
|
|
// shader", so we can just skip doing anything here
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unsupported replacement type from type %d to type %d", fromresource.Namespace,
|
|
resource.Namespace);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::RemoveReplacement(ResourceId id)
|
|
{
|
|
// do actual removal
|
|
GetResourceManager()->RemoveReplacement(id);
|
|
|
|
std::set<ResourceId> recurse;
|
|
|
|
// check if there are any dependent replacements, remove if so
|
|
auto it = std::lower_bound(m_DependentReplacements.begin(), m_DependentReplacements.end(), id,
|
|
ReplacementSearch());
|
|
for(; it != m_DependentReplacements.end();)
|
|
{
|
|
GetResourceManager()->RemoveReplacement(it->second.id);
|
|
recurse.insert(it->second.id);
|
|
|
|
switch(it->second.res.Namespace)
|
|
{
|
|
case eResProgram: glDeleteProgram(it->second.res.name); break;
|
|
case eResProgramPipe: glDeleteProgramPipelines(1, &it->second.res.name); break;
|
|
default: RDCERR("Unexpected resource type to be freed"); break;
|
|
}
|
|
|
|
it = m_DependentReplacements.erase(it);
|
|
}
|
|
|
|
for(auto recurseit = recurse.begin(); recurseit != recurse.end(); ++recurseit)
|
|
{
|
|
// recursive call in case there are any dependents on this resource
|
|
RemoveReplacement(*recurseit);
|
|
}
|
|
}
|
|
|
|
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::SwapBuffers(void *windowHandle)
|
|
{
|
|
if(IsBackgroundCapturing(m_State))
|
|
RenderDoc::Inst().Tick();
|
|
|
|
// don't do anything if no context is active.
|
|
if(GetCtx() == 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
|
|
|
|
GetResourceManager()->FlushPendingDirty();
|
|
|
|
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(windowHandle);
|
|
|
|
ctxdata.AssociateWindow(this, windowHandle);
|
|
}
|
|
|
|
// do this as late as possible to avoid creating objects on contexts
|
|
// that might be shared later (wglShareLists requires contexts to be
|
|
// pristine, so can't create this from wglMakeCurrent)
|
|
if(!ctxdata.ready)
|
|
ctxdata.CreateDebugData(m_Real);
|
|
|
|
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 < ref)
|
|
{
|
|
auto remove = wit;
|
|
++wit;
|
|
|
|
RenderDoc::Inst().RemoveFrameCapturer(cit->first, remove->first);
|
|
|
|
cit->second.windows.erase(remove);
|
|
}
|
|
else
|
|
{
|
|
++wit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(IsBackgroundCapturing(m_State))
|
|
{
|
|
uint32_t overlay = RenderDoc::Inst().GetOverlayBits();
|
|
|
|
if(overlay & eRENDERDOC_Overlay_Enabled)
|
|
{
|
|
RenderTextState textState;
|
|
|
|
textState.Push(m_Real, ctxdata.Modern());
|
|
|
|
int flags = activeWindow ? RenderDoc::eOverlay_ActiveWindow : 0;
|
|
if(ctxdata.Legacy())
|
|
flags |= RenderDoc::eOverlay_CaptureDisabled;
|
|
string 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: Non-core context in use. Compatibility profile 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);
|
|
}
|
|
|
|
if(!overlayText.empty())
|
|
RenderOverlayText(0.0f, 0.0f, overlayText.c_str());
|
|
|
|
textState.Pop(m_Real, ctxdata.Modern());
|
|
|
|
// 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() && m_Real.glGetError)
|
|
ClearGLErrors(m_Real);
|
|
}
|
|
}
|
|
|
|
if(IsActiveCapturing(m_State) && m_AppControlledCapture)
|
|
m_BackbufferImages[windowHandle] = SaveBackbufferImage();
|
|
|
|
if(!activeWindow)
|
|
return;
|
|
|
|
RenderDoc::Inst().SetCurrentDriver(GetDriverType());
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::CreateVRAPITextureSwapChain(GLuint tex, GLenum textureType, GLenum internalformat,
|
|
GLsizei width, GLsizei height, GLint levels)
|
|
{
|
|
GLResource res = TextureRes(GetCtx(), tex);
|
|
ResourceId id = GetResourceManager()->RegisterResource(res);
|
|
|
|
if(IsCaptureMode(m_State))
|
|
{
|
|
GLResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
|
|
RDCASSERT(record);
|
|
|
|
// this chunk is just a dummy, to indicate that this is where the emulated calls below come from
|
|
{
|
|
USE_SCRATCH_SERIALISER();
|
|
SCOPED_SERIALISE_CHUNK(gl_CurChunk);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
|
|
{
|
|
USE_SCRATCH_SERIALISER();
|
|
SCOPED_SERIALISE_CHUNK(GLChunk::glGenTextures);
|
|
Serialise_glGenTextures(ser, 1, &tex);
|
|
|
|
record->AddChunk(scope.Get());
|
|
}
|
|
|
|
gl_CurChunk = GLChunk::glTexParameteri;
|
|
Common_glTextureParameteriEXT(record, textureType, eGL_TEXTURE_MAX_LEVEL, levels);
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->AddLiveResource(id, res);
|
|
}
|
|
|
|
for(GLint i = 0; i < levels; ++i)
|
|
{
|
|
if(textureType == eGL_TEXTURE_2D_ARRAY)
|
|
{
|
|
gl_CurChunk = GLChunk::glTexImage3D;
|
|
Common_glTextureImage3DEXT(id, eGL_TEXTURE_2D_ARRAY, i, internalformat, width, height, 2, 0,
|
|
eGL_RGBA, eGL_UNSIGNED_BYTE, NULL);
|
|
}
|
|
else if(textureType == eGL_TEXTURE_2D)
|
|
{
|
|
gl_CurChunk = GLChunk::glTexImage2D;
|
|
Common_glTextureImage2DEXT(id, eGL_TEXTURE_2D, i, internalformat, width, height, 0, eGL_RGBA,
|
|
eGL_UNSIGNED_BYTE, NULL);
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unexpected textureType (%u) in CreateVRAPITextureSwapChain", textureType);
|
|
}
|
|
|
|
width = RDCMAX(1, (width / 2));
|
|
height = RDCMAX(1, (height / 2));
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::MakeValidContextCurrent(GLWindowingData &prevctx, void *favourWnd)
|
|
{
|
|
if(prevctx.ctx == NULL)
|
|
{
|
|
for(size_t i = m_LastContexts.size(); i > 0; i--)
|
|
{
|
|
// need to find a context for fetching most initial states
|
|
GLWindowingData ctx = m_LastContexts[i - 1];
|
|
|
|
// check this context isn't current elsewhere
|
|
bool usedElsewhere = false;
|
|
for(auto it = m_ActiveContexts.begin(); it != m_ActiveContexts.end(); ++it)
|
|
{
|
|
if(it->second.ctx == ctx.ctx)
|
|
{
|
|
usedElsewhere = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!usedElsewhere)
|
|
{
|
|
prevctx = ctx;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(prevctx.ctx == NULL)
|
|
{
|
|
RDCERR("Couldn't find GL context to make current on this thread %llu.",
|
|
Threading::GetCurrentID());
|
|
}
|
|
|
|
m_ActiveContexts[Threading::GetCurrentID()] = prevctx;
|
|
m_Platform.MakeContextCurrent(prevctx);
|
|
}
|
|
}
|
|
|
|
void WrappedOpenGL::StartFrameCapture(void *dev, void *wnd)
|
|
{
|
|
if(!IsBackgroundCapturing(m_State))
|
|
return;
|
|
|
|
SCOPED_LOCK(GetGLLock());
|
|
|
|
RenderDoc::Inst().SetCurrentDriver(GetDriverType());
|
|
|
|
m_State = CaptureState::ActiveCapturing;
|
|
|
|
m_AppControlledCapture = true;
|
|
|
|
m_Failures = 0;
|
|
m_FailedFrame = 0;
|
|
m_FailedReason = CaptureSucceeded;
|
|
|
|
GLWindowingData prevctx = m_ActiveContexts[Threading::GetCurrentID()];
|
|
GLWindowingData switchctx = prevctx;
|
|
MakeValidContextCurrent(switchctx, wnd);
|
|
|
|
m_FrameCounter = RDCMAX(1 + (uint32_t)m_CapturedFrames.size(), m_FrameCounter);
|
|
|
|
FrameDescription frame;
|
|
frame.frameNumber = m_FrameCounter + 1;
|
|
frame.captureTime = Timing::GetUnixTimestamp();
|
|
RDCEraseEl(frame.stats);
|
|
m_CapturedFrames.push_back(frame);
|
|
|
|
GetResourceManager()->ClearReferencedResources();
|
|
|
|
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_Write);
|
|
|
|
GLuint prevVAO = 0;
|
|
m_Real.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&prevVAO);
|
|
|
|
m_Real.glBindVertexArray(m_FakeVAO);
|
|
|
|
GetResourceManager()->MarkVAOReferenced(VertexArrayRes(NULL, m_FakeVAO), eFrameRef_Write, true);
|
|
|
|
m_Real.glBindVertexArray(prevVAO);
|
|
|
|
GetResourceManager()->PrepareInitialContents();
|
|
|
|
FreeCaptureData();
|
|
|
|
AttemptCapture();
|
|
BeginCaptureFrame();
|
|
|
|
if(switchctx.ctx != prevctx.ctx)
|
|
{
|
|
m_Platform.MakeContextCurrent(prevctx);
|
|
m_ActiveContexts[Threading::GetCurrentID()] = prevctx;
|
|
}
|
|
|
|
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
|
}
|
|
|
|
bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd)
|
|
{
|
|
if(!IsActiveCapturing(m_State))
|
|
return true;
|
|
|
|
SCOPED_LOCK(GetGLLock());
|
|
|
|
CaptureFailReason reason = CaptureSucceeded;
|
|
|
|
GLWindowingData prevctx = m_ActiveContexts[Threading::GetCurrentID()];
|
|
GLWindowingData switchctx = prevctx;
|
|
MakeValidContextCurrent(switchctx, wnd);
|
|
|
|
if(HasSuccessfulCapture(reason))
|
|
{
|
|
RDCLOG("Finished capture, Frame %u", m_FrameCounter);
|
|
|
|
m_Failures = 0;
|
|
m_FailedFrame = 0;
|
|
m_FailedReason = CaptureSucceeded;
|
|
|
|
ContextEndFrame();
|
|
FinishCapture();
|
|
|
|
BackbufferImage *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 && prevctx.ctx != dev) || (wnd != 0 && (void *)prevctx.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(m_FrameCounter, bbim->jpgbuf, bbim->len,
|
|
bbim->thwidth, bbim->thheight);
|
|
|
|
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());
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(SystemChunk::DriverInit, sizeof(GLInitParams) + 16);
|
|
|
|
SERIALISE_ELEMENT(m_InitParams);
|
|
}
|
|
|
|
{
|
|
// remember to update this estimated chunk length if you add more parameters
|
|
SCOPED_SERIALISE_CHUNK(GLChunk::DeviceInitialisation, 32);
|
|
|
|
SERIALISE_ELEMENT(m_FakeVAOID);
|
|
}
|
|
|
|
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("Getting Resource Record");
|
|
|
|
GLResourceRecord *record = m_ResourceManager->GetResourceRecord(m_ContextResourceID);
|
|
|
|
RDCDEBUG("Accumulating context resource list");
|
|
|
|
map<int32_t, Chunk *> recordlist;
|
|
record->Insert(recordlist);
|
|
|
|
RDCDEBUG("Flushing %u records to file serialiser", (uint32_t)recordlist.size());
|
|
|
|
for(auto it = recordlist.begin(); it != recordlist.end(); ++it)
|
|
it->second->Write(ser);
|
|
|
|
RDCDEBUG("Done");
|
|
}
|
|
}
|
|
|
|
RenderDoc::Inst().FinishCaptureWriting(rdc, m_FrameCounter);
|
|
|
|
m_State = CaptureState::BackgroundCapturing;
|
|
|
|
GetResourceManager()->MarkUnwrittenResources();
|
|
|
|
GetResourceManager()->ClearReferencedResources();
|
|
|
|
if(switchctx.ctx != prevctx.ctx)
|
|
{
|
|
m_Platform.MakeContextCurrent(prevctx);
|
|
m_ActiveContexts[Threading::GetCurrentID()] = prevctx;
|
|
}
|
|
|
|
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_FrameCounter, reasonString);
|
|
|
|
m_Failures++;
|
|
|
|
if((RenderDoc::Inst().GetOverlayBits() & eRENDERDOC_Overlay_Enabled))
|
|
{
|
|
ContextData &ctxdata = GetCtxData();
|
|
|
|
RenderTextState textState;
|
|
|
|
textState.Push(m_Real, ctxdata.Modern());
|
|
|
|
RenderOverlayText(0.0f, 0.0f, "Failed to capture frame %u: %s", m_FrameCounter, reasonString);
|
|
|
|
textState.Pop(m_Real, ctxdata.Modern());
|
|
|
|
// 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() && m_Real.glGetError)
|
|
ClearGLErrors(m_Real);
|
|
}
|
|
|
|
m_CapturedFrames.back().frameNumber = m_FrameCounter + 1;
|
|
|
|
CleanupCapture();
|
|
|
|
GetResourceManager()->ClearReferencedResources();
|
|
|
|
// 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 = m_FrameCounter;
|
|
m_FailedReason = reason;
|
|
|
|
m_State = CaptureState::BackgroundCapturing;
|
|
|
|
GetResourceManager()->MarkUnwrittenResources();
|
|
}
|
|
else
|
|
{
|
|
GetResourceManager()->MarkResourceFrameReferenced(m_DeviceResourceID, eFrameRef_Write);
|
|
GetResourceManager()->PrepareInitialContents();
|
|
|
|
AttemptCapture();
|
|
BeginCaptureFrame();
|
|
}
|
|
|
|
if(switchctx.ctx != prevctx.ctx)
|
|
{
|
|
m_Platform.MakeContextCurrent(prevctx);
|
|
m_ActiveContexts[Threading::GetCurrentID()] = prevctx;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage()
|
|
{
|
|
const uint16_t maxSize = 2048;
|
|
|
|
byte *thpixels = NULL;
|
|
uint16_t thwidth = 0;
|
|
uint16_t thheight = 0;
|
|
|
|
if(m_Real.glGetIntegerv && m_Real.glReadBuffer && m_Real.glBindFramebuffer &&
|
|
m_Real.glBindBuffer && m_Real.glReadPixels)
|
|
{
|
|
RDCGLenum prevReadBuf = eGL_BACK;
|
|
GLint prevBuf = 0;
|
|
GLint packBufBind = 0;
|
|
GLint prevPackRowLen = 0;
|
|
GLint prevPackSkipRows = 0;
|
|
GLint prevPackSkipPixels = 0;
|
|
GLint prevPackAlignment = 0;
|
|
m_Real.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&prevReadBuf);
|
|
m_Real.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &prevBuf);
|
|
m_Real.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, &packBufBind);
|
|
m_Real.glGetIntegerv(eGL_PACK_ROW_LENGTH, &prevPackRowLen);
|
|
m_Real.glGetIntegerv(eGL_PACK_SKIP_ROWS, &prevPackSkipRows);
|
|
m_Real.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &prevPackSkipPixels);
|
|
m_Real.glGetIntegerv(eGL_PACK_ALIGNMENT, &prevPackAlignment);
|
|
|
|
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0);
|
|
m_Real.glReadBuffer(eGL_BACK);
|
|
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
|
|
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, 0);
|
|
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, 0);
|
|
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0);
|
|
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, 1);
|
|
|
|
thwidth = (uint16_t)m_InitParams.width;
|
|
thheight = (uint16_t)m_InitParams.height;
|
|
|
|
thpixels = new byte[thwidth * thheight * 4];
|
|
|
|
// GLES only supports GL_RGBA
|
|
m_Real.glReadPixels(0, 0, thwidth, thheight, eGL_RGBA, eGL_UNSIGNED_BYTE, thpixels);
|
|
|
|
// RGBA -> RGB
|
|
for(uint32_t y = 0; y < thheight; y++)
|
|
{
|
|
for(uint32_t x = 0; x < thwidth; x++)
|
|
{
|
|
thpixels[(y * thwidth + x) * 3 + 0] = thpixels[(y * thwidth + x) * 4 + 0];
|
|
thpixels[(y * thwidth + x) * 3 + 1] = thpixels[(y * thwidth + x) * 4 + 1];
|
|
thpixels[(y * thwidth + x) * 3 + 2] = thpixels[(y * thwidth + x) * 4 + 2];
|
|
}
|
|
}
|
|
|
|
// flip the image in-place
|
|
for(uint16_t y = 0; y <= thheight / 2; y++)
|
|
{
|
|
uint16_t flipY = (thheight - 1 - y);
|
|
|
|
for(uint16_t x = 0; x < thwidth; x++)
|
|
{
|
|
byte save[3];
|
|
save[0] = thpixels[(y * thwidth + x) * 3 + 0];
|
|
save[1] = thpixels[(y * thwidth + x) * 3 + 1];
|
|
save[2] = thpixels[(y * thwidth + x) * 3 + 2];
|
|
|
|
thpixels[(y * thwidth + x) * 3 + 0] = thpixels[(flipY * thwidth + x) * 3 + 0];
|
|
thpixels[(y * thwidth + x) * 3 + 1] = thpixels[(flipY * thwidth + x) * 3 + 1];
|
|
thpixels[(y * thwidth + x) * 3 + 2] = thpixels[(flipY * thwidth + x) * 3 + 2];
|
|
|
|
thpixels[(flipY * thwidth + x) * 3 + 0] = save[0];
|
|
thpixels[(flipY * thwidth + x) * 3 + 1] = save[1];
|
|
thpixels[(flipY * thwidth + x) * 3 + 2] = save[2];
|
|
}
|
|
}
|
|
|
|
m_Real.glBindBuffer(eGL_PIXEL_PACK_BUFFER, packBufBind);
|
|
m_Real.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevBuf);
|
|
m_Real.glReadBuffer(prevReadBuf);
|
|
m_Real.glPixelStorei(eGL_PACK_ROW_LENGTH, prevPackRowLen);
|
|
m_Real.glPixelStorei(eGL_PACK_SKIP_ROWS, prevPackSkipRows);
|
|
m_Real.glPixelStorei(eGL_PACK_SKIP_PIXELS, prevPackSkipPixels);
|
|
m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, prevPackAlignment);
|
|
|
|
// scale down if necessary using simple point sampling
|
|
uint16_t resample_width = RDCMIN(maxSize, thwidth);
|
|
resample_width &= ~3; // JPEG encoder gives shear distortion if width is not divisible by 4.
|
|
if(thwidth != resample_width)
|
|
{
|
|
float widthf = float(thwidth);
|
|
float heightf = float(thheight);
|
|
|
|
float aspect = widthf / heightf;
|
|
|
|
// clamp dimensions to a width of resample_width
|
|
thwidth = resample_width;
|
|
thheight = uint16_t(float(thwidth) / aspect);
|
|
|
|
byte *src = thpixels;
|
|
byte *dst = thpixels = new byte[3U * thwidth * thheight];
|
|
|
|
for(uint32_t y = 0; y < thheight; y++)
|
|
{
|
|
for(uint32_t x = 0; x < thwidth; x++)
|
|
{
|
|
float xf = float(x) / float(thwidth);
|
|
float yf = float(y) / float(thheight);
|
|
|
|
byte *pixelsrc =
|
|
&src[3 * uint32_t(xf * widthf) + m_InitParams.width * 3 * uint32_t(yf * heightf)];
|
|
|
|
memcpy(dst, pixelsrc, 3);
|
|
|
|
dst += 3;
|
|
}
|
|
}
|
|
|
|
// src is the raw unscaled pixels, which is no longer needed
|
|
SAFE_DELETE_ARRAY(src);
|
|
}
|
|
}
|
|
|
|
byte *jpgbuf = NULL;
|
|
int len = thwidth * thheight;
|
|
|
|
if(len > 0)
|
|
{
|
|
// jpge::compress_image_to_jpeg_file_in_memory requires at least 1024 bytes
|
|
len = len >= 1024 ? len : 1024;
|
|
|
|
jpgbuf = new byte[len];
|
|
|
|
jpge::params p;
|
|
p.m_quality = 80;
|
|
|
|
bool success =
|
|
jpge::compress_image_to_jpeg_file_in_memory(jpgbuf, len, thwidth, thheight, 3, thpixels, p);
|
|
|
|
if(!success)
|
|
{
|
|
RDCERR("Failed to compress to jpg");
|
|
SAFE_DELETE_ARRAY(jpgbuf);
|
|
thwidth = 0;
|
|
thheight = 0;
|
|
}
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(thpixels);
|
|
|
|
BackbufferImage *bbim = new BackbufferImage();
|
|
bbim->jpgbuf = jpgbuf;
|
|
bbim->len = len;
|
|
bbim->thwidth = thwidth;
|
|
bbim->thheight = thheight;
|
|
|
|
return bbim;
|
|
}
|
|
|
|
template <typename SerialiserType>
|
|
bool WrappedOpenGL::Serialise_CaptureScope(SerialiserType &ser)
|
|
{
|
|
SERIALISE_ELEMENT(m_FrameCounter);
|
|
|
|
SERIALISE_CHECK_READ_ERRORS();
|
|
|
|
if(IsReplayingAndReading())
|
|
{
|
|
m_FrameRecord.frameInfo.frameNumber = m_FrameCounter;
|
|
RDCEraseEl(m_FrameRecord.frameInfo.stats);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedOpenGL::ContextEndFrame()
|
|
{
|
|
USE_SCRATCH_SERIALISER();
|
|
ser.SetDrawChunk();
|
|
SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureEnd);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
void WrappedOpenGL::CleanupCapture()
|
|
{
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
|
|
m_ContextRecord->LockChunks();
|
|
while(m_ContextRecord->HasChunks())
|
|
{
|
|
Chunk *chunk = m_ContextRecord->GetLastChunk();
|
|
|
|
SAFE_DELETE(chunk);
|
|
m_ContextRecord->PopChunk();
|
|
}
|
|
m_ContextRecord->UnlockChunks();
|
|
|
|
m_ContextRecord->FreeParents(GetResourceManager());
|
|
|
|
for(auto it = m_MissingTracks.begin(); it != m_MissingTracks.end(); ++it)
|
|
{
|
|
if(GetResourceManager()->HasResourceRecord(*it))
|
|
GetResourceManager()->MarkDirtyResource(*it);
|
|
}
|
|
|
|
m_MissingTracks.clear();
|
|
}
|
|
|
|
void WrappedOpenGL::FreeCaptureData()
|
|
{
|
|
}
|
|
|
|
void WrappedOpenGL::QueuePrepareInitialState(GLResource res, byte *blob)
|
|
{
|
|
QueuedInitialStateFetch fetch;
|
|
fetch.res = res;
|
|
fetch.blob = blob;
|
|
|
|
auto insertPos =
|
|
std::lower_bound(m_QueuedInitialFetches.begin(), m_QueuedInitialFetches.end(), fetch);
|
|
m_QueuedInitialFetches.insert(insertPos, fetch);
|
|
}
|
|
|
|
void WrappedOpenGL::AttemptCapture()
|
|
{
|
|
m_State = CaptureState::ActiveCapturing;
|
|
|
|
m_DebugMessages.clear();
|
|
|
|
{
|
|
RDCDEBUG("GL Context %llu Attempting capture", GetContextResourceID());
|
|
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
|
|
m_ContextRecord->LockChunks();
|
|
while(m_ContextRecord->HasChunks())
|
|
{
|
|
Chunk *chunk = m_ContextRecord->GetLastChunk();
|
|
|
|
SAFE_DELETE(chunk);
|
|
m_ContextRecord->PopChunk();
|
|
}
|
|
m_ContextRecord->UnlockChunks();
|
|
}
|
|
}
|
|
|
|
template <typename SerialiserType>
|
|
bool WrappedOpenGL::Serialise_BeginCaptureFrame(SerialiserType &ser)
|
|
{
|
|
GLRenderState state(&m_Real);
|
|
|
|
if(ser.IsWriting())
|
|
{
|
|
state.FetchState(this);
|
|
state.MarkReferenced(this, true);
|
|
}
|
|
|
|
SERIALISE_ELEMENT(state);
|
|
|
|
SERIALISE_CHECK_READ_ERRORS();
|
|
|
|
if(IsReplayingAndReading())
|
|
{
|
|
state.ApplyState(this);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedOpenGL::BeginCaptureFrame()
|
|
{
|
|
USE_SCRATCH_SERIALISER();
|
|
SCOPED_SERIALISE_CHUNK(SystemChunk::CaptureBegin);
|
|
|
|
Serialise_BeginCaptureFrame(ser);
|
|
|
|
m_ContextRecord->AddChunk(scope.Get(), 1);
|
|
}
|
|
|
|
void WrappedOpenGL::FinishCapture()
|
|
{
|
|
m_State = CaptureState::BackgroundCapturing;
|
|
|
|
m_DebugMessages.clear();
|
|
|
|
// m_SuccessfulCapture = false;
|
|
}
|
|
|
|
void WrappedOpenGL::AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src,
|
|
std::string 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);
|
|
}
|
|
}
|
|
|
|
std::vector<DebugMessage> WrappedOpenGL::GetDebugMessages()
|
|
{
|
|
std::vector<DebugMessage> ret;
|
|
ret.swap(m_DebugMessages);
|
|
return ret;
|
|
}
|
|
|
|
template <typename SerialiserType>
|
|
void WrappedOpenGL::Serialise_DebugMessages(SerialiserType &ser)
|
|
{
|
|
std::vector<DebugMessage> DebugMessages;
|
|
|
|
if(ser.IsWriting())
|
|
{
|
|
DebugMessages.swap(m_DebugMessages);
|
|
}
|
|
|
|
SERIALISE_ELEMENT(DebugMessages);
|
|
|
|
// 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 && record->UpdateCount > 64)
|
|
return false;
|
|
|
|
// increase update count
|
|
record->UpdateCount++;
|
|
|
|
// if update count is high, mark as dirty
|
|
if(record && 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] && m_Real.glDebugMessageCallback)
|
|
{
|
|
m_Real.glDebugMessageCallback(&DebugSnoopStatic, this);
|
|
#if ENABLED(RDOC_DEVEL)
|
|
m_Real.glEnable(eGL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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))
|
|
{
|
|
DebugMessage msg;
|
|
|
|
msg.messageID = id;
|
|
msg.description = string(message, message + length);
|
|
|
|
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 || type == eGL_DEBUG_TYPE_MARKER)
|
|
{
|
|
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(m_RealDebugFunc && !RenderDoc::Inst().GetCaptureOptions().DebugOutputMute)
|
|
m_RealDebugFunc(source, type, id, severity, length, message, 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)));
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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(FileInitialRead, float(offsetEnd) / float(reader->GetSize()));
|
|
|
|
if((SystemChunk)context == SystemChunk::CaptureScope)
|
|
{
|
|
m_FrameRecord.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);
|
|
|
|
GetResourceManager()->ApplyInitialContents();
|
|
|
|
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;
|
|
|
|
m_FrameRecord.frameInfo.uncompressedFileSize =
|
|
rdc->GetSectionProperties(sectionIdx).uncompressedSize;
|
|
m_FrameRecord.frameInfo.compressedFileSize = rdc->GetSectionProperties(sectionIdx).compressedSize;
|
|
m_FrameRecord.frameInfo.persistentSize = frameDataSize;
|
|
m_FrameRecord.frameInfo.initDataSize = chunkInfos[(GLChunk)SystemChunk::InitialContents].totalsize;
|
|
|
|
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
|
|
m_FrameRecord.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();
|
|
|
|
ResourceId fboId = GetResourceManager()->GetID(FramebufferRes(GetCtx(), m_FakeBB_FBO));
|
|
ResourceId colorId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color));
|
|
ResourceId depthId;
|
|
if(m_FakeBB_DepthStencil)
|
|
depthId = GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_DepthStencil));
|
|
|
|
AddResourceCurChunk(fboId);
|
|
AddResourceCurChunk(colorId);
|
|
AddResourceCurChunk(depthId);
|
|
|
|
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(),
|
|
GLResource(MakeNullResource));
|
|
}
|
|
else if(system == SystemChunk::CaptureScope)
|
|
{
|
|
return Serialise_CaptureScope(ser);
|
|
}
|
|
else if(system == SystemChunk::CaptureEnd)
|
|
{
|
|
if(IsLoading(m_State))
|
|
{
|
|
AddEvent();
|
|
|
|
DrawcallDescription draw;
|
|
draw.name = "SwapBuffers()";
|
|
draw.flags |= DrawFlags::Present;
|
|
|
|
draw.copyDestination = GetResourceManager()->GetOriginalID(
|
|
GetResourceManager()->GetID(TextureRes(GetCtx(), m_FakeBB_Color)));
|
|
|
|
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:
|
|
{
|
|
SERIALISE_ELEMENT(m_FakeVAOID).Named("VAO 0 ID");
|
|
|
|
SERIALISE_CHECK_READ_ERRORS();
|
|
|
|
GetResourceManager()->AddLiveResource(m_FakeVAOID, VertexArrayRes(NULL, 0));
|
|
|
|
AddResource(m_FakeVAOID, ResourceType::StateObject, "");
|
|
GetReplay()->GetResourceDesc(m_FakeVAOID).SetCustomName("Special VAO 0");
|
|
return true;
|
|
}
|
|
|
|
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::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::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:
|
|
return Serialise_glMultiDrawArraysIndirectCountARB(ser, eGL_NONE, 0, 0, 0, 0);
|
|
case GLChunk::glMultiDrawElementsIndirectCountARB:
|
|
return Serialise_glMultiDrawElementsIndirectCountARB(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);
|
|
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::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::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::glRenderbufferStorageMultisampleEXT:
|
|
case GLChunk::glNamedRenderbufferStorageMultisample:
|
|
case GLChunk::glNamedRenderbufferStorageMultisampleEXT:
|
|
return Serialise_glNamedRenderbufferStorageMultisampleEXT(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, 0, eGL_NONE);
|
|
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, 0, eGL_NONE, 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::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: return Serialise_glPolygonOffsetClampEXT(ser, 0, 0, 0);
|
|
case GLChunk::glPrimitiveBoundingBoxEXT:
|
|
case GLChunk::glPrimitiveBoundingBoxOES:
|
|
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::glUniform1fv:
|
|
case GLChunk::glUniform1i:
|
|
case GLChunk::glUniform1iv:
|
|
case GLChunk::glUniform1ui:
|
|
case GLChunk::glUniform1uiEXT:
|
|
case GLChunk::glUniform1uiv:
|
|
case GLChunk::glUniform1uivEXT:
|
|
case GLChunk::glUniform2d:
|
|
case GLChunk::glUniform2dv:
|
|
case GLChunk::glUniform2f:
|
|
case GLChunk::glUniform2fv:
|
|
case GLChunk::glUniform2i:
|
|
case GLChunk::glUniform2iv:
|
|
case GLChunk::glUniform2ui:
|
|
case GLChunk::glUniform2uiEXT:
|
|
case GLChunk::glUniform2uiv:
|
|
case GLChunk::glUniform2uivEXT:
|
|
case GLChunk::glUniform3d:
|
|
case GLChunk::glUniform3dv:
|
|
case GLChunk::glUniform3f:
|
|
case GLChunk::glUniform3fv:
|
|
case GLChunk::glUniform3i:
|
|
case GLChunk::glUniform3iv:
|
|
case GLChunk::glUniform3ui:
|
|
case GLChunk::glUniform3uiEXT:
|
|
case GLChunk::glUniform3uiv:
|
|
case GLChunk::glUniform3uivEXT:
|
|
case GLChunk::glUniform4d:
|
|
case GLChunk::glUniform4dv:
|
|
case GLChunk::glUniform4f:
|
|
case GLChunk::glUniform4fv:
|
|
case GLChunk::glUniform4i:
|
|
case GLChunk::glUniform4iv:
|
|
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::glUniformMatrix2x3dv:
|
|
case GLChunk::glUniformMatrix2x3fv:
|
|
case GLChunk::glUniformMatrix2x4dv:
|
|
case GLChunk::glUniformMatrix2x4fv:
|
|
case GLChunk::glUniformMatrix3dv:
|
|
case GLChunk::glUniformMatrix3fv:
|
|
case GLChunk::glUniformMatrix3x2dv:
|
|
case GLChunk::glUniformMatrix3x2fv:
|
|
case GLChunk::glUniformMatrix3x4dv:
|
|
case GLChunk::glUniformMatrix3x4fv:
|
|
case GLChunk::glUniformMatrix4dv:
|
|
case GLChunk::glUniformMatrix4fv:
|
|
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);
|
|
|
|
// 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::glShaderBinary:
|
|
case GLChunk::glReleaseShaderCompiler:
|
|
case GLChunk::glFrameTerminatorGREMEDY:
|
|
case GLChunk::glDiscardFramebufferEXT:
|
|
case GLChunk::glFinish:
|
|
case GLChunk::glFlush:
|
|
case GLChunk::glInvalidateBufferData:
|
|
case GLChunk::glInvalidateBufferSubData:
|
|
case GLChunk::glInvalidateFramebuffer:
|
|
case GLChunk::glInvalidateNamedFramebufferData:
|
|
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::Max:
|
|
RDCERR("Unexpected chunk, or missing case for processing! Skipping...");
|
|
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());
|
|
|
|
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)
|
|
m_Real.glEndQuery(q);
|
|
else
|
|
m_Real.glEndQueryIndexed(q, j);
|
|
m_ActiveQueries[i][j] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_ActiveConditional)
|
|
{
|
|
m_Real.glEndConditionalRender();
|
|
m_ActiveConditional = false;
|
|
}
|
|
|
|
if(m_ActiveFeedback)
|
|
{
|
|
m_Real.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(
|
|
FileInitialRead, float(m_CurChunkOffset - startOffset) / float(ser.GetReader()->GetSize()));
|
|
|
|
if((SystemChunk)chunktype == SystemChunk::CaptureEnd)
|
|
break;
|
|
|
|
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))
|
|
{
|
|
GetFrameRecord().drawcallList = m_ParentDrawcall.children;
|
|
GetFrameRecord().frameInfo.debugMessages = GetDebugMessages();
|
|
|
|
DrawcallDescription *previous = NULL;
|
|
SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
|
|
|
// 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)
|
|
{
|
|
vector<EventUsage> &v = it->second;
|
|
std::sort(v.begin(), v.end());
|
|
v.erase(std::unique(v.begin(), v.end()), v.end());
|
|
}
|
|
}
|
|
|
|
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:
|
|
{
|
|
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;
|
|
|
|
const GLHookSet &gl = m_Real;
|
|
|
|
GLResourceManager *rm = GetResourceManager();
|
|
|
|
void *ctx = GetCtx();
|
|
|
|
uint32_t e = d.eventID;
|
|
|
|
//////////////////////////////
|
|
// Input
|
|
|
|
if(d.flags & DrawFlags::UseIBuffer)
|
|
{
|
|
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 = 16;
|
|
gl.glGetIntegerv(eGL_MAX_VERTEX_ATTRIB_BINDINGS, &numVBufferBindings);
|
|
|
|
for(GLuint i = 0; i < (GLuint)numVBufferBindings; i++)
|
|
{
|
|
GLuint buffer = GetBoundVertexBuffer(m_Real, i);
|
|
|
|
if(buffer)
|
|
m_ResourceUses[rm->GetID(BufferRes(ctx, buffer))].push_back(
|
|
EventUsage(e, ResourceUsage::VertexBuffer));
|
|
}
|
|
|
|
//////////////////////////////
|
|
// Shaders
|
|
|
|
{
|
|
GLRenderState rs(&m_Real);
|
|
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(m_Real, 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(m_Real, 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.cols == 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 TextureDim::Unknown: texList = NULL; break;
|
|
case TextureDim::Buffer: texList = rs.TexBuffer; break;
|
|
case TextureDim::Texture1D: texList = rs.Tex1D; break;
|
|
case TextureDim::Texture1DArray: texList = rs.Tex1DArray; break;
|
|
case TextureDim::Texture2D: texList = rs.Tex2D; break;
|
|
case TextureDim::TextureRect: texList = rs.TexRect; break;
|
|
case TextureDim::Texture2DArray: texList = rs.Tex2DArray; break;
|
|
case TextureDim::Texture2DMS: texList = rs.Tex2DMS; break;
|
|
case TextureDim::Texture2DMSArray: texList = rs.Tex2DMSArray; break;
|
|
case TextureDim::Texture3D: texList = rs.Tex3D; break;
|
|
case TextureDim::TextureCube: texList = rs.TexCube; break;
|
|
case TextureDim::TextureCubeArray: texList = rs.TexCubeArray; break;
|
|
case TextureDim::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;
|
|
m_Real.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols);
|
|
|
|
RDCEraseEl(draw.outputs);
|
|
|
|
for(GLint i = 0; i < RDCMIN(numCols, 8); i++)
|
|
{
|
|
type = eGL_TEXTURE;
|
|
|
|
m_Real.glGetFramebufferAttachmentParameteriv(
|
|
eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&curCol[i]);
|
|
m_Real.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;
|
|
|
|
m_Real.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
|
|
(GLint *)&curDepth);
|
|
m_Real.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.push_back(apievent);
|
|
}
|
|
|
|
const APIEvent &WrappedOpenGL::GetEvent(uint32_t eventID)
|
|
{
|
|
for(const APIEvent &e : m_Events)
|
|
{
|
|
if(e.eventID >= eventID)
|
|
return e;
|
|
}
|
|
|
|
return m_Events.back();
|
|
}
|
|
|
|
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; i < m_ReplayEventCount; i++)
|
|
GLMarkerRegion::End();
|
|
|
|
GLMarkerRegion::Set("!!!!RenderDoc Internal: Done replay");
|
|
}
|