1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_texture_state.cpp
27 #include "vogl_texture_state.h"
29 #include "vogl_console.h"
30 #include "vogl_data_stream_serializer.h"
31 #include "vogl_dynamic_stream.h"
33 #include "vogl_common.h"
34 #include "vogl_texture_format.h"
35 #include "vogl_shader_utils.h"
36 #include "vogl_msaa_texture.h"
38 #define VOGL_SERIALIZED_TEXTURE_STATE_VERSION 0x101
40 vogl_texture_state::vogl_texture_state()
41 : m_snapshot_handle(0),
45 m_is_unquerable(false),
51 vogl_texture_state::~vogl_texture_state()
58 // TODO: Split this bad boy up into multiple methods
59 // TODO: Add cubemap array support
60 bool vogl_texture_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
64 VOGL_NOTE_UNUSED(remapper);
66 const bool is_target_multisampled = ((target == GL_TEXTURE_2D_MULTISAMPLE) || (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY));
69 //vogl_devel_dump_internal_texture_formats(context_info); exit(0);
73 vogl_scoped_binding_state orig_bindings(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER);
74 orig_bindings.save_textures();
76 vogl_scoped_state_saver pixelstore_state_saver(cGSTPixelStore);
78 vogl_scoped_state_saver pixeltransfer_state_saver;
79 if (!context_info.is_core_profile())
80 pixeltransfer_state_saver.save(cGSTPixelTransfer);
82 vogl_reset_pixel_store_states();
83 if (!context_info.is_core_profile())
84 vogl_reset_pixel_transfer_states();
86 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, 0);
89 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_UNPACK_BUFFER, 0);
94 VOGL_ASSERT(handle <= cUINT32_MAX);
96 m_snapshot_handle = static_cast<uint32>(handle);
99 if (m_target == GL_NONE)
101 // Texture was genned, but not bound to a target yet, so there's nothing more to do.
107 GL_ENTRYPOINT(glBindTexture)(target, m_snapshot_handle);
110 if (m_target == GL_TEXTURE_BUFFER)
113 GL_ENTRYPOINT(glGetIntegerv)(GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB, &handle);
119 GL_ENTRYPOINT(glGetIntegerv)(GL_TEXTURE_BUFFER_FORMAT_ARB, &format);
122 m_params.insert(GL_TEXTURE_INTERNAL_FORMAT, 0, &format, sizeof(format));
128 bool any_gl_errors = false;
130 #define GET_INT(pname) \
133 int values[4] = { 0, 0, 0, 0 }; \
134 GL_ENTRYPOINT(glGetTexParameteriv)(m_target, pname, values); \
135 if (vogl_check_gl_error()) \
136 any_gl_errors = true; \
137 m_params.insert(pname, 0, values, sizeof(values[0])); \
139 #define GET_FLOAT(pname) \
142 float values[4] = { 0, 0, 0, 0 }; \
143 GL_ENTRYPOINT(glGetTexParameterfv)(m_target, pname, values); \
144 if (vogl_check_gl_error()) \
145 any_gl_errors = true; \
146 m_params.insert(pname, 0, values, sizeof(values[0])); \
149 GET_INT(GL_TEXTURE_BASE_LEVEL);
150 GET_INT(GL_TEXTURE_MAX_LEVEL);
152 if (!is_target_multisampled)
154 GET_FLOAT(GL_TEXTURE_BORDER_COLOR);
155 GET_INT(GL_TEXTURE_COMPARE_MODE);
156 GET_INT(GL_TEXTURE_COMPARE_FUNC);
157 GET_FLOAT(GL_TEXTURE_LOD_BIAS);
158 GET_INT(GL_TEXTURE_MIN_FILTER);
159 GET_INT(GL_TEXTURE_MAG_FILTER);
160 GET_FLOAT(GL_TEXTURE_MIN_LOD);
161 GET_FLOAT(GL_TEXTURE_MAX_LOD);
162 GET_INT(GL_TEXTURE_WRAP_S);
163 GET_INT(GL_TEXTURE_WRAP_T);
164 GET_INT(GL_TEXTURE_WRAP_R);
167 GET_INT(GL_TEXTURE_SWIZZLE_R);
168 GET_INT(GL_TEXTURE_SWIZZLE_G);
169 GET_INT(GL_TEXTURE_SWIZZLE_B);
170 GET_INT(GL_TEXTURE_SWIZZLE_A);
171 GET_INT(GL_TEXTURE_SWIZZLE_RGBA);
173 if (!context_info.is_core_profile())
175 GET_INT(GL_GENERATE_MIPMAP);
178 GET_INT(GL_TEXTURE_IMMUTABLE_FORMAT);
180 if (context_info.supports_extension("GL_EXT_texture_filter_anisotropic") && (!is_target_multisampled))
182 GET_FLOAT(GL_TEXTURE_MAX_ANISOTROPY_EXT);
185 if (context_info.supports_extension("GL_EXT_texture_sRGB_decode") && (!is_target_multisampled))
187 GET_INT(GL_TEXTURE_SRGB_DECODE_EXT);
190 if (!context_info.is_core_profile() && context_info.supports_extension("GL_ARB_shadow_ambient"))
192 GET_FLOAT(GL_TEXTURE_COMPARE_FAIL_VALUE_ARB);
195 if (!context_info.is_core_profile())
197 GET_INT(GL_DEPTH_TEXTURE_MODE);
200 //GL_TEXTURE_PRIORITY
201 //GL_TEXTURE_RESIDENT
208 vogl_error_printf("%s: GL error while enumerating texture %" PRIu64 " target %s's params\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
213 int base_level = m_params.get_value<int>(GL_TEXTURE_BASE_LEVEL, 0, 0);
216 vogl_error_printf("%s: Unsupported base level %u while enumerating texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, base_level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
223 vogl_debug_printf("%s: Base level is non-zero (%u) while enumerating texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, base_level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
226 int max_level = m_params.get_value<int>(GL_TEXTURE_MAX_LEVEL, 0, 1000);
228 const GLenum target_to_query = (m_target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : m_target;
230 const int max_supported_mip_levels = vogl_get_max_supported_mip_levels();
232 // Now try to find the highest actually defined mip level before we go any further.
234 for (trial_level = max_supported_mip_levels - 1; trial_level >= 0; trial_level--)
236 GLenum level_internal_fmt = 0;
237 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, trial_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&level_internal_fmt));
239 // Super paranoid here because every driver seems to handle this crap slightly differently and apps lie
240 bool is_valid = true;
242 if (vogl_check_gl_error())
247 // Needed for ACTC's 3D textures, not sure why yet
248 GLint level_width = 0;
249 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, trial_level, GL_TEXTURE_WIDTH, &level_width);
250 if (vogl_check_gl_error())
252 else if (!level_width)
262 // Texture was genned and bound to a target yet, but we couldn't find any valid levels.
263 m_is_unquerable = true;
269 uint num_actual_mip_levels = trial_level + 1;
271 // Try to query the base level
272 if (num_actual_mip_levels != (static_cast<uint>(max_level) + 1U))
274 vogl_warning_printf("%s: Texture's GL_TEXTURE_MAX_LEVEL is %u, but the max defined mip level is %u. Note GL may not act consistently with this texture object, GL texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME,
275 max_level, trial_level,
276 (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
279 GLenum internal_fmt = 0;
280 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, base_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
281 if (vogl_check_gl_error())
283 vogl_error_printf("%s: GL error while enumerating texture %" PRIu64 " target %s's base level GL_TEXTURE_INTERNAL_FORMAT\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target));
288 const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
289 if (!pInternal_tex_fmt)
291 vogl_error_printf("%s: Unknown texture format 0x%04X (%s) while snapshotting texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME,
292 internal_fmt, g_gl_enums.find_gl_image_format_name(internal_fmt), static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target));
297 if ((pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
299 vogl_warning_printf("%s: Don't know how to retrieve texture data of internal format 0x%04X (%s) while snapshotting texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME,
300 internal_fmt, g_gl_enums.find_gl_image_format_name(internal_fmt), static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target));
303 // Note: Mips below the base_level may or may not actually exist, AND the app can dynamically manipulate the base level so we need to try and save everything we can.
304 int base_width = 0, base_height = 0, base_depth = 0;
305 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, base_level, GL_TEXTURE_WIDTH, &base_width);
306 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, base_level, GL_TEXTURE_HEIGHT, &base_height);
307 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, base_level, GL_TEXTURE_DEPTH, &base_depth);
310 if ((base_width < 1) || (base_height < 1) || (base_depth < 1))
312 vogl_warning_printf("%s: Couldn't retrieve base level's width, height and/or depth of GL texture %" PRIu64 " target %s internal format 0x%04X (%s)\n", VOGL_METHOD_NAME,
313 static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target), internal_fmt, g_gl_enums.find_gl_image_format_name(internal_fmt));
315 // Texture has been deleted but it remained bound (but at least in source1 no shaders actually tried to read it), but we can't query anything about it on NV so we're kinda screwed.
316 m_is_unquerable = true;
322 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, base_level, GL_TEXTURE_SAMPLES, reinterpret_cast<GLint *>(&m_num_samples));
324 m_num_samples = math::maximum(m_num_samples, 1U);
326 if (m_num_samples > 1)
328 if (m_num_samples > cMaxSamples)
330 vogl_error_printf("%s: Unsupported number of samples (%u) while snapshotting texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME,
331 m_num_samples, static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target));
335 else if ((target != GL_TEXTURE_2D_MULTISAMPLE) && (target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
337 vogl_error_printf("%s: Unexpected number of samples (%u) while snapshotting texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME,
338 m_num_samples, static_cast<uint64_t>(handle), g_gl_enums.find_gl_name(m_target));
344 uint width = base_width << base_level;
351 case GL_TEXTURE_2D_ARRAY:
352 case GL_TEXTURE_2D_MULTISAMPLE:
353 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
355 height = base_height << base_level;
358 case GL_TEXTURE_CUBE_MAP:
365 height = base_height << base_level;
366 depth = base_depth << base_level;
369 case GL_TEXTURE_RECTANGLE:
371 VOGL_VERIFY(!base_level);
372 height = base_height << base_level;
379 //uint max_possible_mip_levels = (m_target == GL_TEXTURE_RECTANGLE) ? 1 : utils::compute_max_mips(width, height, depth);
381 GLenum image_fmt = pInternal_tex_fmt->m_optimum_get_image_fmt;
382 GLenum image_type = pInternal_tex_fmt->m_optimum_get_image_type;
385 // OK, I can't retrive the default framebuffer's depth/stencil buffer on AMD - all I get is INVALID_OPERATION. Crap. This works fine on NV though.
386 // This workaround didn't work.
387 if (internal_fmt == GL_DEPTH_STENCIL)
389 if (GL_ENTRYPOINT(glGetInternalformativ) && context_info.supports_extension("GL_ARB_internalformat_query"))
391 GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, internal_fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(image_fmt), (GLint *)&image_fmt);
394 GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, internal_fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(image_type), (GLint *)&image_type);
402 GLenum ktx_image_fmt = GL_NONE, ktx_image_type = GL_NONE;
403 if (!pInternal_tex_fmt->m_compressed)
405 ktx_image_fmt = image_fmt;
406 ktx_image_type = image_type;
409 GLenum ktx_tex_target = m_target;
411 if (m_target == GL_TEXTURE_1D)
413 if (!m_textures[0].init_1D(width, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
415 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
420 else if ((m_target == GL_TEXTURE_2D) || (m_target == GL_TEXTURE_RECTANGLE))
422 if (!m_textures[0].init_2D(width, height, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
424 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
429 else if (m_target == GL_TEXTURE_CUBE_MAP)
433 vogl_error_printf("%s: Unsupported cubemap dimensions (%ux%u) for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, width, height, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
438 if (!m_textures[0].init_cubemap(width, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
440 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
445 num_faces = cCubeMapFaces;
447 else if (m_target == GL_TEXTURE_3D)
449 if (!m_textures[0].init_3D(width, height, depth, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
451 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
456 else if (m_target == GL_TEXTURE_1D_ARRAY)
458 if (!m_textures[0].init_1D_array(width, num_actual_mip_levels, base_height, internal_fmt, ktx_image_fmt, ktx_image_type))
460 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
465 else if (m_target == GL_TEXTURE_2D_ARRAY)
467 if (!m_textures[0].init_2D_array(width, height, num_actual_mip_levels, base_depth, internal_fmt, ktx_image_fmt, ktx_image_type))
469 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
474 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE)
476 ktx_tex_target = GL_TEXTURE_2D;
478 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
480 if (!m_textures[sample_index].init_2D(width, height, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
482 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
488 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
490 ktx_tex_target = GL_TEXTURE_2D_ARRAY;
492 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
494 if (!m_textures[sample_index].init_2D_array(width, height, num_actual_mip_levels, base_depth, internal_fmt, ktx_image_fmt, ktx_image_type))
496 vogl_error_printf("%s: Failed initializing KTX texture object for texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
505 vogl_error_printf("%s: Unsupported target, texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
510 VOGL_VERIFY(m_textures[0].get_ogl_internal_fmt() == internal_fmt);
511 if (!pInternal_tex_fmt->m_compressed)
513 VOGL_VERIFY(m_textures[0].get_ogl_fmt() == image_fmt);
514 VOGL_VERIFY(m_textures[0].get_ogl_type() == image_type);
517 // We can't directly get the data of multisampled textures. Instead, copy the MSAA data into X separate non-MSAA textures.
518 vogl::vector<GLuint> split_texture_handles;
519 vogl::vector<GLuint> split_stencil_texture_handles;
521 #define VOGL_FREE_SPLIT_TEXTURES \
522 if (split_texture_handles.size()) { GL_ENTRYPOINT(glDeleteTextures)(split_texture_handles.size(), split_texture_handles.get_ptr()); VOGL_CHECK_GL_ERROR; } \
523 if (split_stencil_texture_handles.size()) { GL_ENTRYPOINT(glDeleteTextures)(split_stencil_texture_handles.size(), split_stencil_texture_handles.get_ptr()); VOGL_CHECK_GL_ERROR; }
525 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
527 // Note: This temporarily switches GL contexts!
528 vogl_msaa_texture_splitter splitter;
530 if (!splitter.init())
532 vogl_error_printf("%s: Failed initializing multisample texture splitter while snapshotting texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
537 if ( (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) ||
538 (pInternal_tex_fmt->m_comp_sizes[cTCRed]) || (pInternal_tex_fmt->m_comp_sizes[cTCGreen]) || (pInternal_tex_fmt->m_comp_sizes[cTCBlue]) || (pInternal_tex_fmt->m_comp_sizes[cTCAlpha]) ||
539 (pInternal_tex_fmt->m_comp_sizes[cTCIntensity]) || (pInternal_tex_fmt->m_comp_sizes[cTCLuminance]) )
541 if (!splitter.split(target, static_cast<GLuint>(handle), split_texture_handles))
543 vogl_error_printf("%s: Failed splitting multisample texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
549 if (pInternal_tex_fmt->m_comp_sizes[cTCStencil])
551 GLuint temp_msaa_color_tex = 0;
552 if (!splitter.copy_stencil_samples_to_color(target, static_cast<GLuint>(handle), temp_msaa_color_tex))
554 vogl_error_printf("%s: Failed splitting multisample texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
559 bool status = splitter.split(target, temp_msaa_color_tex, split_stencil_texture_handles);
561 GL_ENTRYPOINT(glDeleteTextures)(1, &temp_msaa_color_tex);
564 temp_msaa_color_tex = 0;
568 vogl_error_printf("%s: Failed splitting multisample texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
575 for (uint face = 0; face < num_faces; face++)
577 GLenum face_target_to_query = m_target;
578 if (m_target == GL_TEXTURE_CUBE_MAP)
579 face_target_to_query = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
581 m_level_params[face].resize(num_actual_mip_levels);
583 for (uint level = 0; level < num_actual_mip_levels; level++)
585 GLenum level_internal_fmt = 0;
586 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&level_internal_fmt));
588 bool is_valid = true;
589 if (vogl_check_gl_error())
591 else if (level_internal_fmt != internal_fmt)
596 // Needed for ACTC's 3D textures, not sure why yet
597 GLint level_width = 0;
598 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, level, GL_TEXTURE_WIDTH, &level_width);
599 if (vogl_check_gl_error())
601 else if (!level_width)
603 else if (level_width != math::maximum<int>(width >> level, 1))
613 vogl_state_vector level_params;
615 bool any_gl_errors = false;
617 // TODO: Check for core vs. compat profiles and not query the old stuff
618 #define GET_INT(gl_enum) \
621 int values[4] = { 0, 0, 0, 0 }; \
622 GL_ENTRYPOINT(glGetTexLevelParameteriv)(face_target_to_query, level, gl_enum, values); \
623 if (vogl_check_gl_error()) \
624 any_gl_errors = true; \
625 level_params.insert(gl_enum, 0, values, sizeof(values[0])); \
628 GET_INT(GL_TEXTURE_WIDTH);
629 GET_INT(GL_TEXTURE_HEIGHT);
630 GET_INT(GL_TEXTURE_DEPTH);
631 GET_INT(GL_TEXTURE_INTERNAL_FORMAT);
634 vogl_error_printf("%s: Failed retrieving face %u level %u's internal format and/or width while enumerating texture %" PRIu64 " target %s's level params\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
636 VOGL_FREE_SPLIT_TEXTURES
640 GET_INT(GL_TEXTURE_SAMPLES);
641 GET_INT(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS);
643 GET_INT(GL_TEXTURE_RED_SIZE);
644 GET_INT(GL_TEXTURE_GREEN_SIZE);
645 GET_INT(GL_TEXTURE_BLUE_SIZE);
646 GET_INT(GL_TEXTURE_ALPHA_SIZE);
647 GET_INT(GL_TEXTURE_DEPTH_SIZE);
648 GET_INT(GL_TEXTURE_STENCIL_SIZE);
649 GET_INT(GL_TEXTURE_LUMINANCE_SIZE);
650 GET_INT(GL_TEXTURE_INTENSITY_SIZE);
651 GET_INT(GL_TEXTURE_SHARED_SIZE);
652 GET_INT(GL_TEXTURE_COMPRESSED);
654 if (context_info.supports_extension("GL_ARB_depth_texture"))
656 GET_INT(GL_TEXTURE_DEPTH_SIZE);
657 GET_INT(GL_TEXTURE_DEPTH_TYPE);
660 if (context_info.supports_extension("GL_EXT_packed_depth_stencil"))
661 GET_INT(GL_TEXTURE_STENCIL_SIZE_EXT);
663 if (m_target == GL_TEXTURE_BUFFER)
665 GET_INT(GL_TEXTURE_BUFFER_DATA_STORE_BINDING);
666 GET_INT(GL_TEXTURE_BUFFER_OFFSET);
667 GET_INT(GL_TEXTURE_BUFFER_SIZE);
670 bool is_compressed = level_params.get_value<bool>(GL_TEXTURE_COMPRESSED);
674 level_params.insert(GL_TEXTURE_COMPRESSED_IMAGE_SIZE, 0, &value, sizeof(value));
678 GET_INT(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
684 vogl_warning_printf("%s: One or more GL errors while enumerating texture %" PRIu64 " target %s's level params\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
687 if ((level_params.get_value<int>(GL_TEXTURE_WIDTH) == 0) ||
688 (level_params.get_value<int>(GL_TEXTURE_HEIGHT) == 0) ||
689 (level_params.get_value<int>(GL_TEXTURE_DEPTH) == 0) ||
690 (level_params.get_value<GLenum>(GL_TEXTURE_INTERNAL_FORMAT) != internal_fmt))
692 vogl_error_printf("%s: Failed retrieving level %u's parameters while enumerating texture %" PRIu64 " target %s's level params\n", VOGL_METHOD_NAME, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
694 VOGL_FREE_SPLIT_TEXTURES
698 size_t size_in_bytes = level_params.get_value<uint>(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
699 if (pInternal_tex_fmt->m_compressed)
703 vogl_error_printf("%s: Failed retrieving level %u's compressed size while enumerating texture %" PRIu64 " target %s's level params\n", VOGL_METHOD_NAME, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
705 VOGL_FREE_SPLIT_TEXTURES
713 vogl_error_printf("%s: Unexpected compressed size on level %u's while enumerating texture %" PRIu64 " target %s's level params\n", VOGL_METHOD_NAME, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
715 VOGL_FREE_SPLIT_TEXTURES
720 m_level_params[face][level] = level_params;
728 // Now grab the data from each face, mipmap level, and slice/layer and supply it to the KTX texture object.
729 for (uint face = 0; face < num_faces; face++)
731 GLenum face_target_to_query = m_target;
732 if (m_target == GL_TEXTURE_CUBE_MAP)
733 face_target_to_query = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
735 // Query available mip levels and add them to the texture.
736 for (uint level = 0; level < num_actual_mip_levels; level++)
738 const vogl_state_vector &level_params = m_level_params[face][level];
740 if (!level_params.find(GL_TEXTURE_WIDTH))
742 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
744 // Insert placeholder images for the missing texture levels
745 int image_size = m_textures[sample_index].get_expected_image_size(level);
746 temp_img.resize(image_size);
748 if ((ktx_tex_target == GL_TEXTURE_1D_ARRAY) || (ktx_tex_target == GL_TEXTURE_2D_ARRAY))
750 VOGL_ASSERT(base_depth);
751 uint num_array_elements = base_depth;
753 if (ktx_tex_target == GL_TEXTURE_1D_ARRAY)
755 VOGL_ASSERT(base_height);
756 num_array_elements = base_height;
759 for (uint array_index = 0; array_index < num_array_elements; array_index++)
761 m_textures[sample_index].add_image(level, array_index, face, 0, temp_img.get_ptr(), image_size);
766 int level_depth = (target == GL_TEXTURE_3D) ? math::maximum<int>(1, depth >> level) : 1;
768 for (int zslice = 0; zslice < level_depth; zslice++)
770 m_textures[sample_index].add_image(level, 0, face, zslice, temp_img.get_ptr(), temp_img.size());
777 int level_width = level_params.get_value<int>(GL_TEXTURE_WIDTH);
778 int level_height = level_params.get_value<int>(GL_TEXTURE_HEIGHT);
779 int level_depth = level_params.get_value<int>(GL_TEXTURE_DEPTH);
781 int size_in_bytes = level_params.get_value<uint>(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
783 if (!pInternal_tex_fmt->m_compressed)
785 VOGL_ASSERT(!size_in_bytes);
787 size_t size_in_bytes64 = vogl_get_image_size(image_fmt, image_type, level_width, level_height, level_depth);
788 if (!size_in_bytes64)
790 vogl_error_printf("%s: Failed computing image size of face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
792 VOGL_FREE_SPLIT_TEXTURES
796 if (size_in_bytes64 > static_cast<size_t>(cINT32_MAX))
798 vogl_error_printf("%s: Image size too large for face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
800 VOGL_FREE_SPLIT_TEXTURES
804 size_in_bytes = static_cast<int>(size_in_bytes64);
807 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
809 GLenum get_target = face_target_to_query;
811 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
813 GL_ENTRYPOINT(glBindTexture)(ktx_tex_target, split_texture_handles[sample_index]);
816 get_target = ktx_tex_target;
819 const uint num_guard_bytes = 2;
820 if (!temp_img.try_resize(size_in_bytes + num_guard_bytes))
822 vogl_error_printf("%s: Out of memory while trying to retrieve texture data, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
824 VOGL_FREE_SPLIT_TEXTURES
828 // Write a pattern after the buffer to detect buffer size computation screwups.
829 if (size_in_bytes >= 4)
831 temp_img[size_in_bytes - 4] = 0x67;
832 temp_img[size_in_bytes - 3] = 0xCC;
833 temp_img[size_in_bytes - 2] = 0xD4;
834 temp_img[size_in_bytes - 1] = 0xF9;
837 temp_img[size_in_bytes] = 0xDE;
838 temp_img[size_in_bytes + 1] = 0xAD;
840 if (pInternal_tex_fmt->m_compressed)
842 GL_ENTRYPOINT(glGetCompressedTexImage)(get_target, level, temp_img.get_ptr());
846 GL_ENTRYPOINT(glGetTexImage)(get_target, level, image_fmt, image_type, temp_img.get_ptr());
849 if (vogl_check_gl_error())
851 vogl_error_printf("%s: Failed retrieving image data for face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
853 VOGL_FREE_SPLIT_TEXTURES
857 if (size_in_bytes >= 4)
859 if ((temp_img[size_in_bytes - 4] == 0x67) && (temp_img[size_in_bytes - 3] == 0xCC) &&
860 (temp_img[size_in_bytes - 2] == 0xD4) && (temp_img[size_in_bytes - 1] == 0xF9))
862 vogl_error_printf("%s: Image data retrieval may have failed for face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
866 VOGL_VERIFY((temp_img[size_in_bytes] == 0xDE) && (temp_img[size_in_bytes + 1] == 0xAD));
868 temp_img.try_resize(size_in_bytes);
870 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
872 if (split_stencil_texture_handles.size())
874 size_t split_color_size_in_bytes64 = vogl_get_image_size(GL_RGBA, GL_UNSIGNED_BYTE, level_width, level_height, level_depth);
876 if (!split_color_size_in_bytes64)
878 vogl_error_printf("%s: Failed computing image size of face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
880 VOGL_FREE_SPLIT_TEXTURES
884 if (split_color_size_in_bytes64 > static_cast<size_t>(cINT32_MAX))
886 vogl_error_printf("%s: Image size too large for face %u level %u, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, face, level, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
888 VOGL_FREE_SPLIT_TEXTURES
892 uint8_vec stencil_image_data(static_cast<uint>(split_color_size_in_bytes64));
894 GL_ENTRYPOINT(glBindTexture)(ktx_tex_target, split_stencil_texture_handles[sample_index]);
897 GL_ENTRYPOINT(glGetTexImage)(ktx_tex_target, level, GL_RGBA, GL_UNSIGNED_BYTE, stencil_image_data.get_ptr());
900 switch (internal_fmt)
902 case GL_DEPTH_STENCIL: // GL_UNSIGNED_INT_24_8
903 case GL_DEPTH24_STENCIL8: // GL_UNSIGNED_INT_24_8
905 for (uint y = 0; y < height; y++)
907 for (uint x = 0; x < width; x++)
909 uint ofs = (x * sizeof(uint32)) + (y * width * sizeof(uint32));
911 if ((ofs < stencil_image_data.size()) && (ofs < temp_img.size()))
913 uint8 *pSrc = stencil_image_data.get_ptr() + ofs;
914 uint8 *pDest = temp_img.get_ptr() + ofs;
922 case GL_DEPTH32F_STENCIL8: // GL_FLOAT_32_UNSIGNED_INT_24_8_REV
923 case GL_DEPTH32F_STENCIL8_NV: // GL_FLOAT_32_UNSIGNED_INT_24_8_REV
925 for (uint y = 0; y < height; y++)
927 for (uint x = 0; x < width; x++)
929 uint ofs = (x * sizeof(uint32)) + (y * width * sizeof(uint32));
931 if ((ofs < stencil_image_data.size()) && ((ofs + 3) < temp_img.size()))
933 uint8 *pSrc = stencil_image_data.get_ptr() + ofs;
934 uint8 *pDest = temp_img.get_ptr() + ofs;
945 vogl_warning_printf("%s: Unable to set stencil data in texture %" PRIu64 "\n", VOGL_METHOD_NAME, (uint64_t)handle);
953 if (ktx_tex_target == GL_TEXTURE_3D)
955 uint zslice_size = size_in_bytes;
958 VOGL_ASSERT((size_in_bytes % level_depth) == 0);
959 zslice_size = size_in_bytes / level_depth;
960 VOGL_ASSERT(zslice_size);
963 VOGL_ASSERT((size_in_bytes % zslice_size) == 0);
966 for (int zslice = 0; zslice < level_depth; zslice++)
968 m_textures[sample_index].add_image(level, 0, face, zslice, temp_img.get_ptr() + cur_ofs, zslice_size);
969 cur_ofs += zslice_size;
971 VOGL_ASSERT(static_cast<int>(cur_ofs) == size_in_bytes);
973 else if ((ktx_tex_target == GL_TEXTURE_1D_ARRAY) || (ktx_tex_target == GL_TEXTURE_2D_ARRAY))
975 VOGL_ASSERT(base_depth);
976 uint num_array_elements = base_depth;
978 if (ktx_tex_target == GL_TEXTURE_1D_ARRAY)
980 num_array_elements = base_height;
983 VOGL_ASSERT((size_in_bytes % num_array_elements) == 0);
984 uint element_size = size_in_bytes / num_array_elements;
985 VOGL_ASSERT(element_size);
986 VOGL_ASSERT((size_in_bytes % element_size) == 0);
989 for (uint array_index = 0; array_index < num_array_elements; array_index++)
991 m_textures[sample_index].add_image(level, array_index, face, 0, temp_img.get_ptr() + cur_ofs, element_size);
992 cur_ofs += element_size;
997 m_textures[sample_index].add_image_grant_ownership(level, 0, face, 0, temp_img);
1007 GL_ENTRYPOINT(glBindTexture)(target, m_snapshot_handle);
1008 VOGL_CHECK_GL_ERROR;
1010 // TODO: Add more key/values?
1011 m_textures[0].add_key_value("VOGL_TARGET", dynamic_string(cVarArg, "%u", m_target).get_ptr());
1012 m_textures[0].add_key_value("VOGL_BASE_LEVEL", dynamic_string(cVarArg, "%u", m_params.get_value<int>(GL_TEXTURE_BASE_LEVEL)).get_ptr());
1013 m_textures[0].add_key_value("VOGL_MAX_LEVEL", dynamic_string(cVarArg, "%u", m_params.get_value<int>(GL_TEXTURE_MAX_LEVEL)).get_ptr());
1015 bool x_flipped = false, y_flipped = true;
1016 dynamic_string ktx_orient_str(cVarArg, "S=%c,T=%c", x_flipped ? 'l' : 'r', y_flipped ? 'u' : 'd');
1017 m_textures[0].add_key_value("KTXorientation", ktx_orient_str.get_ptr());
1019 if (!m_textures[0].consistency_check())
1021 vogl_error_printf("%s: Internal error: KTX texture failed internal consistency check, texture %" PRIu64 " target %s\n", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
1023 VOGL_FREE_SPLIT_TEXTURES
1027 VOGL_FREE_SPLIT_TEXTURES
1034 bool vogl_texture_state::set_tex_parameter(GLenum pname) const
1038 const vogl_state_data *pData = m_params.find(pname);
1041 // We only return false on a GL error.
1050 if (pData->get_num_elements() > cMaxElements)
1056 if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble))
1059 pData->get_float(fvals);
1060 if (pData->get_num_elements() == 1)
1061 GL_ENTRYPOINT(glTexParameterf)(m_target, pname, fvals[0]);
1063 GL_ENTRYPOINT(glTexParameterfv)(m_target, pname, fvals);
1068 pData->get_int(ivals);
1069 if (pData->get_num_elements() == 1)
1070 GL_ENTRYPOINT(glTexParameteri)(m_target, pname, ivals[0]);
1072 GL_ENTRYPOINT(glTexParameteriv)(m_target, pname, ivals);
1075 return !vogl_check_gl_error();
1078 // Note: We'll need the remapper for buffer textures.
1079 bool vogl_texture_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
1086 VOGL_CHECK_GL_ERROR;
1088 vogl_msaa_texture_splitter splitter;
1090 vogl_scoped_binding_state orig_bindings(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER);
1091 orig_bindings.save_textures();
1093 vogl_scoped_state_saver pixeltransfer_state_saver(cGSTPixelStore);
1095 if (!context_info.is_core_profile())
1096 pixeltransfer_state_saver.save(cGSTPixelTransfer);
1098 vogl_reset_pixel_store_states();
1100 if (!context_info.is_core_profile())
1101 vogl_reset_pixel_transfer_states();
1103 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, 0);
1104 VOGL_CHECK_GL_ERROR;
1106 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_UNPACK_BUFFER, 0);
1107 VOGL_CHECK_GL_ERROR;
1109 bool created_handle = false;
1113 GLuint handle32 = 0;
1114 GL_ENTRYPOINT(glGenTextures)(1, &handle32);
1115 if ((vogl_check_gl_error()) || (!handle32))
1119 remapper.declare_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle, handle, m_target);
1120 if (!remapper.is_default_remapper())
1122 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle) == handle);
1125 created_handle = true;
1128 if (m_target == GL_NONE)
1130 // Texture has not been bound to a target yet, so we're done.
1134 uint face = 0, level = 0;
1137 uint tex_width = 0, tex_height = 0, tex_depth = 0, total_actual_levels = 0, num_faces = 0;
1138 int base_level = 0, max_level = 0;
1139 VOGL_NOTE_UNUSED(base_level);
1140 VOGL_NOTE_UNUSED(max_level);
1141 bool is_immutable_format = false, is_compressed = false;
1142 GLenum internal_fmt = GL_NONE;
1144 const ktx_texture &tex0 = m_textures[0];
1146 GL_ENTRYPOINT(glBindTexture)(m_target, static_cast<uint32>(handle));
1147 if (vogl_check_gl_error())
1150 if (m_target == GL_TEXTURE_BUFFER)
1154 GLuint buffer_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_buffer));
1157 vogl_error_printf("%s: Failed remapping buffer handle for buffer texture trace handle %u GL handle %" PRIu64 ", trace buffer %u GL buffer %u\n", VOGL_METHOD_NAME, m_snapshot_handle, static_cast<uint64_t>(handle), m_buffer, buffer_handle);
1161 internal_fmt = m_params.get_value<int>(GL_TEXTURE_INTERNAL_FORMAT);
1165 vogl_error_printf("%s: Failed retrieving GL_TEXTURE_INTERNAL_FORMAT for buffer texture trace handle %u GL handle %" PRIu64 ", trace buffer %u GL buffer %u\n", VOGL_METHOD_NAME, m_snapshot_handle, static_cast<uint64_t>(handle), m_buffer, buffer_handle);
1169 GL_ENTRYPOINT(glTexBuffer)(m_target, internal_fmt, buffer_handle);
1170 VOGL_CHECK_GL_ERROR;
1177 any_failures = false;
1179 #define SET_INT(pname) \
1182 if (!set_tex_parameter(pname)) \
1183 any_failures = true; \
1185 #define SET_FLOAT(pname) \
1188 if (!set_tex_parameter(pname)) \
1189 any_failures = true; \
1191 SET_INT(GL_TEXTURE_BASE_LEVEL);
1192 SET_INT(GL_TEXTURE_MAX_LEVEL);
1193 SET_FLOAT(GL_TEXTURE_BORDER_COLOR);
1194 SET_INT(GL_TEXTURE_COMPARE_MODE);
1195 SET_INT(GL_TEXTURE_COMPARE_FUNC);
1196 SET_INT(GL_TEXTURE_MIN_FILTER);
1197 SET_INT(GL_TEXTURE_MAG_FILTER);
1198 if (m_target != GL_TEXTURE_RECTANGLE)
1200 SET_FLOAT(GL_TEXTURE_LOD_BIAS);
1201 SET_FLOAT(GL_TEXTURE_MIN_LOD);
1202 SET_FLOAT(GL_TEXTURE_MAX_LOD);
1204 SET_INT(GL_TEXTURE_SWIZZLE_RGBA);
1205 SET_INT(GL_TEXTURE_WRAP_S);
1206 SET_INT(GL_TEXTURE_WRAP_T);
1207 SET_INT(GL_TEXTURE_WRAP_R);
1209 if (context_info.supports_extension("GL_EXT_texture_filter_anisotropic"))
1211 SET_FLOAT(GL_TEXTURE_MAX_ANISOTROPY_EXT);
1214 if (context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
1216 SET_INT(GL_TEXTURE_SRGB_DECODE_EXT);
1219 if (!context_info.is_core_profile() && context_info.supports_extension("GL_ARB_shadow_ambient"))
1221 SET_FLOAT(GL_TEXTURE_COMPARE_FAIL_VALUE_ARB);
1224 if (!context_info.is_core_profile())
1226 SET_INT(GL_DEPTH_TEXTURE_MODE);
1230 // GL_TEXTURE_PRIORITY
1231 // GL_TEXTURE_RESIDENT
1233 if ((m_is_unquerable) || (!m_textures[0].is_valid()))
1235 if (m_params.get_value<int>(GL_GENERATE_MIPMAP))
1237 GL_ENTRYPOINT(glGenerateMipmap)(m_target);
1243 if (m_num_samples < 1)
1246 tex_width = tex0.get_width();
1247 tex_height = tex0.get_height();
1248 tex_depth = tex0.get_depth();
1249 total_actual_levels = tex0.get_num_mips();
1250 base_level = m_params.get_value<int>(GL_TEXTURE_BASE_LEVEL);
1251 max_level = m_params.get_value<int>(GL_TEXTURE_MAX_LEVEL);
1253 is_immutable_format = m_params.get_value<int>(GL_TEXTURE_IMMUTABLE_FORMAT) != 0;
1254 is_compressed = tex0.is_compressed();
1255 internal_fmt = tex0.get_ogl_internal_fmt();
1257 num_faces = (m_target == GL_TEXTURE_CUBE_MAP) ? cCubeMapFaces : 1;
1260 for (uint sample_index = 1; sample_index < m_num_samples; sample_index++)
1262 const ktx_texture &cmp_tex = m_textures[sample_index];
1264 if ( (!cmp_tex.is_valid()) || (tex_width != cmp_tex.get_width()) || (tex_height != cmp_tex.get_height()) || (tex_depth != cmp_tex.get_depth()) ||
1265 (tex0.get_num_mips() != cmp_tex.get_num_mips()) || (tex0.get_array_size() != cmp_tex.get_array_size()) || (tex0.get_num_faces() != cmp_tex.get_num_faces()) ||
1266 (tex0.get_ogl_fmt() != cmp_tex.get_ogl_fmt()) || (tex0.get_ogl_type() != cmp_tex.get_ogl_type()) || (tex0.get_ogl_internal_fmt() != cmp_tex.get_ogl_internal_fmt()) )
1268 vogl_error_printf("%s: MSAA consistency error\n", VOGL_METHOD_NAME);
1275 // TODO: Support immutable textures
1276 if (is_immutable_format)
1278 vogl_warning_printf_once("%s: TODO: Support immutable textures (texture will be created non-immutable)\n", VOGL_METHOD_NAME);
1281 for (face = 0; face < num_faces; face++)
1283 for (level = 0; level < total_actual_levels; level++)
1285 const vogl_state_vector &level_params = m_level_params[face][level];
1287 if (!level_params.find(GL_TEXTURE_WIDTH))
1290 int level_width = level_params.get_value<int>(GL_TEXTURE_WIDTH);
1291 int level_height = level_params.get_value<int>(GL_TEXTURE_HEIGHT);
1292 int level_depth = level_params.get_value<int>(GL_TEXTURE_DEPTH);
1293 int level_samples = level_params.get_value<int>(GL_TEXTURE_SAMPLES);
1295 GLenum level_internal_fmt = level_params.get_value<int>(GL_TEXTURE_INTERNAL_FORMAT);
1297 if ((level_width < 1) || (level_height < 1) || (level_depth < 1) || (level_internal_fmt != internal_fmt))
1299 vogl_error_printf("%s: Consistency error\n", VOGL_METHOD_NAME);
1304 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
1306 if ((is_compressed) || (level_samples != static_cast<int>(m_num_samples)) || (level != 0))
1308 vogl_error_printf("%s: Multisampled texture consistency error\n", VOGL_METHOD_NAME);
1313 if (m_target == GL_TEXTURE_2D_MULTISAMPLE)
1315 GL_ENTRYPOINT(glTexImage2DMultisample)(m_target, m_num_samples, internal_fmt, level_width, level_height, level_params.get_value<GLenum>(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS));
1316 VOGL_CHECK_GL_ERROR;
1318 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
1320 GL_ENTRYPOINT(glTexImage3DMultisample)(m_target, m_num_samples, internal_fmt, level_width, level_height, tex0.get_array_size(), level_params.get_value<GLenum>(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS));
1321 VOGL_CHECK_GL_ERROR;
1325 vogl_error_printf("%s: Unexpected target error\n", VOGL_METHOD_NAME);
1330 // Note: This changes the active GL context to a work context!
1331 if (!splitter.init())
1333 vogl_error_printf("%s: Failed initializing texture splitter object!\n", VOGL_METHOD_NAME);
1338 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
1340 const uint8_vec &src_img = m_textures[sample_index].get_image_data(level, 0, face, 0);
1341 VOGL_ASSERT(src_img.size());
1343 GLuint src_texture = 0;
1344 GL_ENTRYPOINT(glGenTextures)(1, &src_texture);
1345 VOGL_CHECK_GL_ERROR;
1347 const GLenum src_target = (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
1349 GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
1350 VOGL_CHECK_GL_ERROR;
1352 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAX_LEVEL, 0);
1353 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1354 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1355 VOGL_CHECK_GL_ERROR;
1357 if (src_target == GL_TEXTURE_2D_ARRAY)
1359 uint array_size = tex0.get_array_size();
1362 temp_img.reserve(src_img.size() * array_size);
1364 for (uint array_index = 0; array_index < array_size; array_index++)
1366 temp_img.append(m_textures[sample_index].get_image_data(level, array_index, face, 0));
1369 GL_ENTRYPOINT(glTexImage3D)(src_target, level, level_internal_fmt, level_width, level_height, array_size, 0, tex0.get_ogl_fmt(), tex0.get_ogl_type(), temp_img.get_ptr());
1370 VOGL_CHECK_GL_ERROR;
1374 GL_ENTRYPOINT(glTexImage2D)(src_target, level, level_internal_fmt, level_width, level_height, 0, tex0.get_ogl_fmt(), tex0.get_ogl_type(), src_img.get_ptr());
1375 VOGL_CHECK_GL_ERROR;
1378 bool status = splitter.combine(src_texture, sample_index, m_target, static_cast<uint32>(handle));
1380 GL_ENTRYPOINT(glBindTexture)(src_target, 0);
1381 VOGL_CHECK_GL_ERROR;
1383 GL_ENTRYPOINT(glDeleteTextures)(1, &src_texture);
1384 VOGL_CHECK_GL_ERROR;
1393 // Check if dest texture has stencil
1394 bool has_stencil = utils::is_in_set<GLenum, GLenum>(internal_fmt, GL_DEPTH_STENCIL, GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8_NV);
1395 bool is_reversed_fmt = utils::is_in_set<GLenum, GLenum>(internal_fmt, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8_NV);
1399 GLenum temp_color_format = GL_RGBA;
1400 GLenum temp_color_type = is_reversed_fmt ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_INT_8_8_8_8_REV;
1402 GLuint temp_color_texture = 0;
1403 GL_ENTRYPOINT(glGenTextures)(1, &temp_color_texture);
1404 VOGL_CHECK_GL_ERROR;
1406 const GLenum src_target = (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
1408 GL_ENTRYPOINT(glBindTexture)(src_target, temp_color_texture);
1409 VOGL_CHECK_GL_ERROR;
1411 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAX_LEVEL, 0);
1412 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1413 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1414 VOGL_CHECK_GL_ERROR;
1416 if (src_target == GL_TEXTURE_2D_ARRAY)
1418 uint array_size = tex0.get_array_size();
1421 temp_img.reserve(src_img.size() * array_size);
1423 for (uint array_index = 0; array_index < array_size; array_index++)
1425 temp_img.append(m_textures[sample_index].get_image_data(level, array_index, face, 0));
1428 GL_ENTRYPOINT(glTexImage3D)(src_target, level, GL_RGBA, level_width, level_height, array_size, 0, temp_color_format, temp_color_type, temp_img.get_ptr());
1429 VOGL_CHECK_GL_ERROR;
1433 GL_ENTRYPOINT(glTexImage2D)(src_target, level, GL_RGBA, level_width, level_height, 0, temp_color_format, temp_color_type, src_img.get_ptr());
1434 VOGL_CHECK_GL_ERROR;
1437 bool status = splitter.copy_color_sample_to_stencil(temp_color_texture, sample_index, m_target, static_cast<uint32>(handle));
1439 GL_ENTRYPOINT(glBindTexture)(src_target, 0);
1440 VOGL_CHECK_GL_ERROR;
1442 GL_ENTRYPOINT(glDeleteTextures)(1, &temp_color_texture);
1443 VOGL_CHECK_GL_ERROR;
1449 vogl_error_printf("%s: Failed copying MSAA stencil samples from temp color texture to stencil", VOGL_METHOD_NAME);
1460 GLenum target_to_set = m_target;
1461 if (m_target == GL_TEXTURE_CUBE_MAP)
1462 target_to_set = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
1464 if (level_samples > 1)
1466 vogl_error_printf("%s: GL_TEXTURE_SAMPLES consistency error\n", VOGL_METHOD_NAME);
1471 const uint8_vec &src_img = tex0.get_image_data(level, 0, face, 0);
1472 VOGL_ASSERT(src_img.size());
1480 GL_ENTRYPOINT(glCompressedTexImage1D)(target_to_set, level, level_internal_fmt, level_width, 0, src_img.size(), src_img.get_ptr());
1484 GL_ENTRYPOINT(glTexImage1D)(target_to_set, level, level_internal_fmt, level_width, 0, tex0.get_ogl_fmt(), tex0.get_ogl_type(), src_img.get_ptr());
1490 case GL_TEXTURE_RECTANGLE:
1491 case GL_TEXTURE_CUBE_MAP:
1492 case GL_TEXTURE_1D_ARRAY:
1494 if (m_target == GL_TEXTURE_1D_ARRAY)
1496 uint array_size = tex0.get_array_size();
1497 for (uint array_index = 0; array_index < array_size; array_index++)
1499 temp_img.append(tex0.get_image_data(level, array_index, face, 0));
1501 level_height = array_size;
1510 GL_ENTRYPOINT(glCompressedTexImage2D)(target_to_set, level, level_internal_fmt, level_width, level_height, 0, src_img.size(), temp_img.get_ptr());
1514 GL_ENTRYPOINT(glTexImage2D)(target_to_set, level, level_internal_fmt, level_width, level_height, 0, tex0.get_ogl_fmt(), tex0.get_ogl_type(), temp_img.get_ptr());
1519 case GL_TEXTURE_2D_ARRAY:
1523 temp_img.reserve(src_img.size() * level_depth);
1525 if (m_target == GL_TEXTURE_3D)
1527 for (int zslice = 0; zslice < level_depth; zslice++)
1529 temp_img.append(tex0.get_image_data(level, 0, face, zslice));
1535 uint array_size = tex0.get_array_size();
1536 for (uint array_index = 0; array_index < array_size; array_index++)
1538 temp_img.append(tex0.get_image_data(level, array_index, face, 0));
1540 level_depth = array_size;
1545 GL_ENTRYPOINT(glCompressedTexImage3D)(target_to_set, level, level_internal_fmt, level_width, level_height, level_depth, 0, temp_img.size(), temp_img.get_ptr());
1549 GL_ENTRYPOINT(glTexImage3D)(target_to_set, level, level_internal_fmt, level_width, level_height, level_depth, 0, tex0.get_ogl_fmt(), tex0.get_ogl_type(), temp_img.get_ptr());
1557 vogl_error_printf("%s: Unsupported target type %d\n", VOGL_METHOD_NAME, m_target);
1562 if (vogl_check_gl_error())
1564 vogl_error_printf("%s: Failed creating texture image\n", VOGL_METHOD_NAME);
1572 if (m_params.get_value<int>(GL_GENERATE_MIPMAP))
1574 GL_ENTRYPOINT(glGenerateMipmap)(m_target);
1575 vogl_debug_printf("%s: Generating mipmaps for texture, snapshot handle %u GL handle %u\n", VOGL_METHOD_NAME, m_snapshot_handle, (uint)handle);
1583 vogl_warning_printf("%s: One or more texture params could not be set on trace texture %u, GL texture %" PRIu64 " target %s, dimensions %ux%ux%u, internal format %s\n", VOGL_METHOD_NAME,
1584 m_snapshot_handle, (uint64_t)handle, g_gl_enums.find_gl_name(m_target), tex_width, tex_height, tex_depth, g_gl_enums.find_gl_image_format_name(internal_fmt));
1590 vogl_error_printf("%s: Failed restoring trace texture %u, GL texture %" PRIu64 " target %s, while processing face %u level %u, dimensions %ux%ux%u, internal format %s\n", VOGL_METHOD_NAME,
1591 m_snapshot_handle, (uint64_t)handle, g_gl_enums.find_gl_name(m_target), face, level, tex_width, tex_height, tex_depth, g_gl_enums.find_gl_image_format_name(internal_fmt));
1593 GL_ENTRYPOINT(glBindTexture)(m_target, 0);
1594 VOGL_CHECK_GL_ERROR;
1598 remapper.delete_handle_and_object(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle, handle);
1606 bool vogl_texture_state::remap_handles(vogl_handle_remapper &remapper)
1613 m_snapshot_handle = static_cast<uint32>(remapper.remap_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle));
1617 m_buffer = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_buffer));
1623 void vogl_texture_state::clear()
1627 m_snapshot_handle = 0;
1633 for (uint i = 0; i < cMaxSamples; i++)
1634 m_textures[i].clear();
1637 for (uint i = 0; i < VOGL_ARRAY_SIZE(m_level_params); i++)
1638 m_level_params[i].clear();
1640 m_is_unquerable = false;
1644 bool vogl_texture_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
1651 node.add_key_value("version", VOGL_SERIALIZED_TEXTURE_STATE_VERSION);
1652 node.add_key_value("handle", m_snapshot_handle);
1653 node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
1654 node.add_key_value("is_unquerable", m_is_unquerable);
1655 node.add_key_value("buffer", m_buffer);
1656 node.add_key_value("samples", m_num_samples);
1658 if ((!m_is_unquerable) && (m_target != GL_NONE))
1660 json_node &tex_params_obj = node.add_object("tex_params");
1661 if (!m_params.serialize(tex_params_obj, blob_manager))
1664 if ((m_target != GL_TEXTURE_BUFFER) && (m_num_samples))
1666 json_node &textures_array_node = node.add_array("textures");
1668 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
1670 json_node &texture_node = textures_array_node.add_object();
1672 const ktx_texture &tex = m_textures[sample_index];
1674 const char *pTex_type = utils::map_value(static_cast<int>(m_target), "tex",
1675 GL_TEXTURE_1D, "tex_1d",
1676 GL_TEXTURE_2D, "tex_2d",
1677 GL_TEXTURE_3D, "tex_3d",
1678 GL_TEXTURE_CUBE_MAP, "tex_cube",
1679 GL_TEXTURE_RECTANGLE, "tex_rect",
1680 GL_TEXTURE_2D_ARRAY, "tex_2d_array",
1681 GL_TEXTURE_1D_ARRAY, "tex_1d_array",
1682 GL_TEXTURE_BUFFER, "tex_buffer",
1683 GL_TEXTURE_2D_MULTISAMPLE, "tex_2d_multisample",
1684 GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "tex_2d_multisample_array",
1685 GL_TEXTURE_CUBE_MAP_ARRAY, "tex_cube_array");
1687 uint actual_mip_levels = m_params.get_value<GLint>(GL_TEXTURE_MAX_LEVEL) + 1;
1689 actual_mip_levels = math::minimum(actual_mip_levels, tex.get_num_mips());
1691 dynamic_string prefix;
1695 prefix.format("%s_%u_levels_%u_%s", pTex_type, tex.get_width(), actual_mip_levels, g_gl_enums.find_gl_name(tex.get_ogl_internal_fmt()));
1697 case GL_TEXTURE_RECTANGLE:
1699 prefix.format("%s_%ux%u_levels_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1702 prefix.format("%s_%ux%ux%u_levels_%u_%s", pTex_type, tex.get_width(), tex.get_height(), tex.get_depth(), actual_mip_levels, g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1704 case GL_TEXTURE_1D_ARRAY:
1705 prefix.format("%s_%u_levels_%u_arraysize_%u_%s", pTex_type, tex.get_width(), actual_mip_levels, tex.get_array_size(), g_gl_enums.find_gl_name(tex.get_ogl_internal_fmt()));
1707 case GL_TEXTURE_2D_ARRAY:
1708 prefix.format("%s_%ux%u_levels_%u_arraysize_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, tex.get_array_size(), g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1710 case GL_TEXTURE_2D_MULTISAMPLE:
1711 prefix.format("%s_%ux%u_levels_%u_sample_%u_of_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, sample_index, m_num_samples, g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1713 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1714 prefix.format("%s_%ux%u_levels_%u_sample_%u_of_%u_arraysize_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, sample_index, m_num_samples, tex.get_array_size(), g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1716 case GL_TEXTURE_CUBE_MAP:
1717 prefix.format("%s_%ux%u_levels_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1719 case GL_TEXTURE_CUBE_MAP_ARRAY:
1720 prefix.format("%s_%ux%u_levels_%u_arraysize_%u_%s", pTex_type, tex.get_width(), tex.get_height(), actual_mip_levels, tex.get_array_size(), g_gl_enums.find_gl_image_format_name(tex.get_ogl_internal_fmt()));
1727 dynamic_stream dyn_stream;
1728 data_stream_serializer serializer(dyn_stream);
1729 if (!tex.write_to_stream(serializer))
1732 dyn_stream.seek(0, false);
1734 dynamic_string blob_id(blob_manager.add_stream_compute_unique_id(dyn_stream, prefix.get_ptr(), "ktx"));
1735 if (blob_id.is_empty())
1740 texture_node.add_key_value("texture_data_blob_id", blob_id);
1743 json_node &level_params_array = node.add_array("level_params");
1744 for (uint face = 0; face < m_textures[0].get_num_faces(); face++)
1746 for (uint level = 0; level < m_textures[0].get_num_mips(); level++)
1748 json_node &level_param_array_value = level_params_array.add_object();
1749 if (m_target == GL_TEXTURE_CUBE_MAP)
1750 level_param_array_value.add_key_value("face", face);
1751 level_param_array_value.add_key_value("level", level);
1753 json_node ¶ms_node = level_param_array_value.add_object("params");
1754 if (!m_level_params[face][level].serialize(params_node, blob_manager))
1764 bool vogl_texture_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
1770 if ((!node.has_key("handle")) || (!node.has_key("target")))
1773 m_snapshot_handle = node.value_as_uint32("handle");
1774 m_target = vogl_get_json_value_as_enum(node, "target");
1775 m_is_unquerable = node.value_as_bool("is_unquerable");
1776 m_buffer = node.value_as_uint32("buffer");
1777 m_num_samples = node.value_as_uint32("samples", 1);
1780 if (!utils::is_in_set(static_cast<int>(m_target), GL_NONE, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY,
1781 GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BUFFER, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
1786 const json_node *pTex_params_obj = node.find_child_object("tex_params");
1787 if (pTex_params_obj)
1789 if (!m_params.deserialize(*pTex_params_obj, blob_manager))
1793 if ((!m_is_unquerable) && (m_target != GL_NONE) && (m_target != GL_TEXTURE_BUFFER))
1795 if (node.has_key("texture_data_blob_id"))
1797 if (m_num_samples != 1)
1800 dynamic_string blob_id(node.value_as_string_ptr("texture_data_blob_id"));
1801 if (blob_id.is_empty())
1804 dynamic_stream tex_data;
1805 if (!blob_manager.get(blob_id, tex_data.get_buf()))
1808 data_stream_serializer serializer(&tex_data);
1809 if (!m_textures[0].read_from_stream(serializer))
1812 else if (node.has_array("textures"))
1814 const json_node *pTextures_array_node = node.find_child_array("textures");
1815 if ((!pTextures_array_node) || (!pTextures_array_node->size()) || (pTextures_array_node->size() > cMaxSamples))
1818 for (uint i = 0; i < pTextures_array_node->size(); i++)
1820 const json_node *pTexture_node = pTextures_array_node->get_child(i);
1824 dynamic_string blob_id(pTexture_node->value_as_string_ptr("texture_data_blob_id"));
1825 if (blob_id.is_empty())
1828 dynamic_stream tex_data;
1829 if (!blob_manager.get(blob_id, tex_data.get_buf()))
1832 data_stream_serializer serializer(&tex_data);
1833 if (!m_textures[i].read_from_stream(serializer))
1842 const json_node *pLevel_params_array = node.find_child_array("level_params");
1843 if (pLevel_params_array)
1845 for (uint i = 0; i < pLevel_params_array->size(); i++)
1847 const json_node *pLevel_params_node = pLevel_params_array->get_value_as_object(i);
1848 if (!pLevel_params_node)
1851 uint face = pLevel_params_node->value_as_uint32("face");
1854 if ((m_target != GL_TEXTURE_CUBE_MAP) || (face > cCubeMapFaces))
1858 uint level = pLevel_params_node->value_as_uint32("level");
1859 // obviously crazy level
1863 if (level >= m_level_params[face].size())
1864 m_level_params[face].resize(level + 1);
1866 const json_node *pParams_node = pLevel_params_node->find_child_object("params");
1870 if (!m_level_params[face][level].deserialize(*pParams_node, blob_manager))
1883 bool vogl_texture_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
1887 if ((!m_is_valid) || (!rhs_obj.is_valid()))
1890 if (rhs_obj.get_type() != cGLSTTexture)
1893 const vogl_texture_state &rhs = static_cast<const vogl_texture_state &>(rhs_obj);
1901 CMP(m_is_unquerable);
1906 for (uint i = 0; i < cCubeMapFaces; i++)
1907 CMP(m_level_params[i]);
1911 for (uint i = 0; i < m_num_samples; i++)
1913 if (m_textures[i].is_valid() != rhs.m_textures[i].is_valid())
1915 if (m_textures[i] != rhs.m_textures[i])