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;
386 GLenum ktx_image_fmt = GL_NONE, ktx_image_type = GL_NONE;
387 if (!pInternal_tex_fmt->m_compressed)
389 ktx_image_fmt = image_fmt;
390 ktx_image_type = image_type;
393 GLenum ktx_tex_target = m_target;
395 if (m_target == GL_TEXTURE_1D)
397 if (!m_textures[0].init_1D(width, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
399 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));
404 else if ((m_target == GL_TEXTURE_2D) || (m_target == GL_TEXTURE_RECTANGLE))
406 if (!m_textures[0].init_2D(width, height, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
408 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));
413 else if (m_target == GL_TEXTURE_CUBE_MAP)
417 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));
422 if (!m_textures[0].init_cubemap(width, 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 num_faces = cCubeMapFaces;
431 else if (m_target == GL_TEXTURE_3D)
433 if (!m_textures[0].init_3D(width, height, depth, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
435 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));
440 else if (m_target == GL_TEXTURE_1D_ARRAY)
442 if (!m_textures[0].init_1D_array(width, num_actual_mip_levels, base_height, internal_fmt, ktx_image_fmt, ktx_image_type))
444 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));
449 else if (m_target == GL_TEXTURE_2D_ARRAY)
451 if (!m_textures[0].init_2D_array(width, height, num_actual_mip_levels, base_depth, internal_fmt, ktx_image_fmt, ktx_image_type))
453 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));
458 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE)
460 ktx_tex_target = GL_TEXTURE_2D;
462 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
464 if (!m_textures[sample_index].init_2D(width, height, num_actual_mip_levels, internal_fmt, ktx_image_fmt, ktx_image_type))
466 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));
472 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
474 ktx_tex_target = GL_TEXTURE_2D_ARRAY;
476 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
478 if (!m_textures[sample_index].init_2D_array(width, height, num_actual_mip_levels, base_depth, internal_fmt, ktx_image_fmt, ktx_image_type))
480 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));
489 vogl_error_printf("%s: Unsupported target, texture %" PRIu64 " target %s", VOGL_METHOD_NAME, (uint64_t)handle, g_gl_enums.find_gl_name(m_target));
494 VOGL_VERIFY(m_textures[0].get_ogl_internal_fmt() == internal_fmt);
495 if (!pInternal_tex_fmt->m_compressed)
497 VOGL_VERIFY(m_textures[0].get_ogl_fmt() == image_fmt);
498 VOGL_VERIFY(m_textures[0].get_ogl_type() == image_type);
501 // We can't directly get the data of multisampled textures. Instead, copy the MSAA data into X separate non-MSAA textures.
502 vogl::vector<GLuint> split_texture_handles;
503 vogl::vector<GLuint> split_stencil_texture_handles;
505 #define VOGL_FREE_SPLIT_TEXTURES \
506 if (split_texture_handles.size()) { GL_ENTRYPOINT(glDeleteTextures)(split_texture_handles.size(), split_texture_handles.get_ptr()); VOGL_CHECK_GL_ERROR; } \
507 if (split_stencil_texture_handles.size()) { GL_ENTRYPOINT(glDeleteTextures)(split_stencil_texture_handles.size(), split_stencil_texture_handles.get_ptr()); VOGL_CHECK_GL_ERROR; }
509 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
511 // Note: This temporarily switches GL contexts!
512 vogl_msaa_texture_splitter splitter;
514 if (!splitter.init())
516 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));
521 if ( (pInternal_tex_fmt->m_comp_sizes[cTCDepth]) ||
522 (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]) ||
523 (pInternal_tex_fmt->m_comp_sizes[cTCIntensity]) || (pInternal_tex_fmt->m_comp_sizes[cTCLuminance]) )
525 if (!splitter.split(target, static_cast<GLuint>(handle), split_texture_handles))
527 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));
533 if (pInternal_tex_fmt->m_comp_sizes[cTCStencil])
535 GLuint temp_msaa_color_tex = 0;
536 if (!splitter.copy_stencil_samples_to_color(target, static_cast<GLuint>(handle), temp_msaa_color_tex))
538 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));
543 bool status = splitter.split(target, temp_msaa_color_tex, split_stencil_texture_handles);
545 GL_ENTRYPOINT(glDeleteTextures)(1, &temp_msaa_color_tex);
548 temp_msaa_color_tex = 0;
552 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 for (uint face = 0; face < num_faces; face++)
561 GLenum face_target_to_query = m_target;
562 if (m_target == GL_TEXTURE_CUBE_MAP)
563 face_target_to_query = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
565 m_level_params[face].resize(num_actual_mip_levels);
567 for (uint level = 0; level < num_actual_mip_levels; level++)
569 GLenum level_internal_fmt = 0;
570 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&level_internal_fmt));
572 bool is_valid = true;
573 if (vogl_check_gl_error())
575 else if (level_internal_fmt != internal_fmt)
580 // Needed for ACTC's 3D textures, not sure why yet
581 GLint level_width = 0;
582 GL_ENTRYPOINT(glGetTexLevelParameteriv)(target_to_query, level, GL_TEXTURE_WIDTH, &level_width);
583 if (vogl_check_gl_error())
585 else if (!level_width)
587 else if (level_width != math::maximum<int>(width >> level, 1))
597 vogl_state_vector level_params;
599 bool any_gl_errors = false;
601 // TODO: Check for core vs. compat profiles and not query the old stuff
602 #define GET_INT(gl_enum) \
605 int values[4] = { 0, 0, 0, 0 }; \
606 GL_ENTRYPOINT(glGetTexLevelParameteriv)(face_target_to_query, level, gl_enum, values); \
607 if (vogl_check_gl_error()) \
608 any_gl_errors = true; \
609 level_params.insert(gl_enum, 0, values, sizeof(values[0])); \
612 GET_INT(GL_TEXTURE_WIDTH);
613 GET_INT(GL_TEXTURE_HEIGHT);
614 GET_INT(GL_TEXTURE_DEPTH);
615 GET_INT(GL_TEXTURE_INTERNAL_FORMAT);
618 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));
620 VOGL_FREE_SPLIT_TEXTURES
624 GET_INT(GL_TEXTURE_SAMPLES);
625 GET_INT(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS);
627 GET_INT(GL_TEXTURE_RED_SIZE);
628 GET_INT(GL_TEXTURE_GREEN_SIZE);
629 GET_INT(GL_TEXTURE_BLUE_SIZE);
630 GET_INT(GL_TEXTURE_ALPHA_SIZE);
631 GET_INT(GL_TEXTURE_DEPTH_SIZE);
632 GET_INT(GL_TEXTURE_STENCIL_SIZE);
633 GET_INT(GL_TEXTURE_LUMINANCE_SIZE);
634 GET_INT(GL_TEXTURE_INTENSITY_SIZE);
635 GET_INT(GL_TEXTURE_SHARED_SIZE);
636 GET_INT(GL_TEXTURE_COMPRESSED);
638 if (context_info.supports_extension("GL_ARB_depth_texture"))
640 GET_INT(GL_TEXTURE_DEPTH_SIZE);
641 GET_INT(GL_TEXTURE_DEPTH_TYPE);
644 if (context_info.supports_extension("GL_EXT_packed_depth_stencil"))
645 GET_INT(GL_TEXTURE_STENCIL_SIZE_EXT);
647 if (m_target == GL_TEXTURE_BUFFER)
649 GET_INT(GL_TEXTURE_BUFFER_DATA_STORE_BINDING);
650 GET_INT(GL_TEXTURE_BUFFER_OFFSET);
651 GET_INT(GL_TEXTURE_BUFFER_SIZE);
654 bool is_compressed = level_params.get_value<bool>(GL_TEXTURE_COMPRESSED);
658 level_params.insert(GL_TEXTURE_COMPRESSED_IMAGE_SIZE, 0, &value, sizeof(value));
662 GET_INT(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
668 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));
671 if ((level_params.get_value<int>(GL_TEXTURE_WIDTH) == 0) ||
672 (level_params.get_value<int>(GL_TEXTURE_HEIGHT) == 0) ||
673 (level_params.get_value<int>(GL_TEXTURE_DEPTH) == 0) ||
674 (level_params.get_value<GLenum>(GL_TEXTURE_INTERNAL_FORMAT) != internal_fmt))
676 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));
678 VOGL_FREE_SPLIT_TEXTURES
682 size_t size_in_bytes = level_params.get_value<uint>(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
683 if (pInternal_tex_fmt->m_compressed)
687 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));
689 VOGL_FREE_SPLIT_TEXTURES
697 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));
699 VOGL_FREE_SPLIT_TEXTURES
704 m_level_params[face][level] = level_params;
712 // Now grab the data from each face, mipmap level, and slice/layer and supply it to the KTX texture object.
713 for (uint face = 0; face < num_faces; face++)
715 GLenum face_target_to_query = m_target;
716 if (m_target == GL_TEXTURE_CUBE_MAP)
717 face_target_to_query = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
719 // Query available mip levels and add them to the texture.
720 for (uint level = 0; level < num_actual_mip_levels; level++)
722 const vogl_state_vector &level_params = m_level_params[face][level];
724 if (!level_params.find(GL_TEXTURE_WIDTH))
726 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
728 // Insert placeholder images for the missing texture levels
729 int image_size = m_textures[sample_index].get_expected_image_size(level);
730 temp_img.resize(image_size);
732 if ((ktx_tex_target == GL_TEXTURE_1D_ARRAY) || (ktx_tex_target == GL_TEXTURE_2D_ARRAY))
734 VOGL_ASSERT(base_depth);
735 uint num_array_elements = base_depth;
737 if (ktx_tex_target == GL_TEXTURE_1D_ARRAY)
739 VOGL_ASSERT(base_height);
740 num_array_elements = base_height;
743 for (uint array_index = 0; array_index < num_array_elements; array_index++)
745 m_textures[sample_index].add_image(level, array_index, face, 0, temp_img.get_ptr(), image_size);
750 int level_depth = (target == GL_TEXTURE_3D) ? math::maximum<int>(1, depth >> level) : 1;
752 for (int zslice = 0; zslice < level_depth; zslice++)
754 m_textures[sample_index].add_image(level, 0, face, zslice, temp_img.get_ptr(), temp_img.size());
761 int level_width = level_params.get_value<int>(GL_TEXTURE_WIDTH);
762 int level_height = level_params.get_value<int>(GL_TEXTURE_HEIGHT);
763 int level_depth = level_params.get_value<int>(GL_TEXTURE_DEPTH);
765 int size_in_bytes = level_params.get_value<uint>(GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
767 if (!pInternal_tex_fmt->m_compressed)
769 VOGL_ASSERT(!size_in_bytes);
771 size_t size_in_bytes64 = vogl_get_image_size(pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, level_width, level_height, level_depth);
772 if (!size_in_bytes64)
774 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));
776 VOGL_FREE_SPLIT_TEXTURES
780 if (size_in_bytes64 > static_cast<size_t>(cINT32_MAX))
782 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));
784 VOGL_FREE_SPLIT_TEXTURES
788 size_in_bytes = static_cast<int>(size_in_bytes64);
791 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
793 GLenum get_target = face_target_to_query;
795 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
797 GL_ENTRYPOINT(glBindTexture)(ktx_tex_target, split_texture_handles[sample_index]);
800 get_target = ktx_tex_target;
803 const uint num_guard_bytes = 2;
804 if (!temp_img.try_resize(size_in_bytes + num_guard_bytes))
806 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));
808 VOGL_FREE_SPLIT_TEXTURES
812 // Write a pattern after the buffer to detect buffer size computation screwups.
813 if (size_in_bytes >= 4)
815 temp_img[size_in_bytes - 4] = 0x67;
816 temp_img[size_in_bytes - 3] = 0xCC;
817 temp_img[size_in_bytes - 2] = 0xD4;
818 temp_img[size_in_bytes - 1] = 0xF9;
821 temp_img[size_in_bytes] = 0xDE;
822 temp_img[size_in_bytes + 1] = 0xAD;
824 if (pInternal_tex_fmt->m_compressed)
826 GL_ENTRYPOINT(glGetCompressedTexImage)(get_target, level, temp_img.get_ptr());
830 GL_ENTRYPOINT(glGetTexImage)(get_target, level, pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, temp_img.get_ptr());
833 if (vogl_check_gl_error())
835 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));
837 VOGL_FREE_SPLIT_TEXTURES
841 if (size_in_bytes >= 4)
843 if ((temp_img[size_in_bytes - 4] == 0x67) && (temp_img[size_in_bytes - 3] == 0xCC) &&
844 (temp_img[size_in_bytes - 2] == 0xD4) && (temp_img[size_in_bytes - 1] == 0xF9))
846 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));
850 VOGL_VERIFY((temp_img[size_in_bytes] == 0xDE) && (temp_img[size_in_bytes + 1] == 0xAD));
852 temp_img.try_resize(size_in_bytes);
854 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
856 if (split_stencil_texture_handles.size())
858 size_t split_color_size_in_bytes64 = vogl_get_image_size(GL_RGBA, GL_UNSIGNED_BYTE, level_width, level_height, level_depth);
860 if (!split_color_size_in_bytes64)
862 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));
864 VOGL_FREE_SPLIT_TEXTURES
868 if (split_color_size_in_bytes64 > static_cast<size_t>(cINT32_MAX))
870 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));
872 VOGL_FREE_SPLIT_TEXTURES
876 uint8_vec stencil_image_data(static_cast<uint>(split_color_size_in_bytes64));
878 GL_ENTRYPOINT(glBindTexture)(ktx_tex_target, split_stencil_texture_handles[sample_index]);
881 GL_ENTRYPOINT(glGetTexImage)(ktx_tex_target, level, GL_RGBA, GL_UNSIGNED_BYTE, stencil_image_data.get_ptr());
884 switch (internal_fmt)
886 case GL_DEPTH_STENCIL: // GL_UNSIGNED_INT_24_8
887 case GL_DEPTH24_STENCIL8: // GL_UNSIGNED_INT_24_8
889 for (uint y = 0; y < height; y++)
891 for (uint x = 0; x < width; x++)
893 uint ofs = (x * sizeof(uint32)) + (y * width * sizeof(uint32));
895 if ((ofs < stencil_image_data.size()) && (ofs < temp_img.size()))
897 uint8 *pSrc = stencil_image_data.get_ptr() + ofs;
898 uint8 *pDest = temp_img.get_ptr() + ofs;
906 case GL_DEPTH32F_STENCIL8: // GL_FLOAT_32_UNSIGNED_INT_24_8_REV
907 case GL_DEPTH32F_STENCIL8_NV: // GL_FLOAT_32_UNSIGNED_INT_24_8_REV
909 for (uint y = 0; y < height; y++)
911 for (uint x = 0; x < width; x++)
913 uint ofs = (x * sizeof(uint32)) + (y * width * sizeof(uint32));
915 if ((ofs < stencil_image_data.size()) && ((ofs + 3) < temp_img.size()))
917 uint8 *pSrc = stencil_image_data.get_ptr() + ofs;
918 uint8 *pDest = temp_img.get_ptr() + ofs;
929 vogl_warning_printf("%s: Unable to set stencil data in texture %" PRIu64 "\n", VOGL_METHOD_NAME, (uint64_t)handle);
937 if (ktx_tex_target == GL_TEXTURE_3D)
939 uint zslice_size = size_in_bytes;
942 VOGL_ASSERT((size_in_bytes % level_depth) == 0);
943 zslice_size = size_in_bytes / level_depth;
944 VOGL_ASSERT(zslice_size);
947 VOGL_ASSERT((size_in_bytes % zslice_size) == 0);
950 for (int zslice = 0; zslice < level_depth; zslice++)
952 m_textures[sample_index].add_image(level, 0, face, zslice, temp_img.get_ptr() + cur_ofs, zslice_size);
953 cur_ofs += zslice_size;
955 VOGL_ASSERT(static_cast<int>(cur_ofs) == size_in_bytes);
957 else if ((ktx_tex_target == GL_TEXTURE_1D_ARRAY) || (ktx_tex_target == GL_TEXTURE_2D_ARRAY))
959 VOGL_ASSERT(base_depth);
960 uint num_array_elements = base_depth;
962 if (ktx_tex_target == GL_TEXTURE_1D_ARRAY)
964 num_array_elements = base_height;
967 VOGL_ASSERT((size_in_bytes % num_array_elements) == 0);
968 uint element_size = size_in_bytes / num_array_elements;
969 VOGL_ASSERT(element_size);
970 VOGL_ASSERT((size_in_bytes % element_size) == 0);
973 for (uint array_index = 0; array_index < num_array_elements; array_index++)
975 m_textures[sample_index].add_image(level, array_index, face, 0, temp_img.get_ptr() + cur_ofs, element_size);
976 cur_ofs += element_size;
981 m_textures[sample_index].add_image_grant_ownership(level, 0, face, 0, temp_img);
991 GL_ENTRYPOINT(glBindTexture)(target, m_snapshot_handle);
994 // TODO: Add more key/values?
995 m_textures[0].add_key_value("VOGL_TARGET", dynamic_string(cVarArg, "%u", m_target).get_ptr());
996 m_textures[0].add_key_value("VOGL_BASE_LEVEL", dynamic_string(cVarArg, "%u", m_params.get_value<int>(GL_TEXTURE_BASE_LEVEL)).get_ptr());
997 m_textures[0].add_key_value("VOGL_MAX_LEVEL", dynamic_string(cVarArg, "%u", m_params.get_value<int>(GL_TEXTURE_MAX_LEVEL)).get_ptr());
999 bool x_flipped = false, y_flipped = true;
1000 dynamic_string ktx_orient_str(cVarArg, "S=%c,T=%c", x_flipped ? 'l' : 'r', y_flipped ? 'u' : 'd');
1001 m_textures[0].add_key_value("KTXorientation", ktx_orient_str.get_ptr());
1003 if (!m_textures[0].consistency_check())
1005 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));
1007 VOGL_FREE_SPLIT_TEXTURES
1011 VOGL_FREE_SPLIT_TEXTURES
1018 bool vogl_texture_state::set_tex_parameter(GLenum pname) const
1022 const vogl_state_data *pData = m_params.find(pname);
1025 // We only return false on a GL error.
1034 if (pData->get_num_elements() > cMaxElements)
1040 if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble))
1043 pData->get_float(fvals);
1044 if (pData->get_num_elements() == 1)
1045 GL_ENTRYPOINT(glTexParameterf)(m_target, pname, fvals[0]);
1047 GL_ENTRYPOINT(glTexParameterfv)(m_target, pname, fvals);
1052 pData->get_int(ivals);
1053 if (pData->get_num_elements() == 1)
1054 GL_ENTRYPOINT(glTexParameteri)(m_target, pname, ivals[0]);
1056 GL_ENTRYPOINT(glTexParameteriv)(m_target, pname, ivals);
1059 return !vogl_check_gl_error();
1062 // Note: We'll need the remapper for buffer textures.
1063 bool vogl_texture_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
1070 VOGL_CHECK_GL_ERROR;
1072 vogl_msaa_texture_splitter splitter;
1074 vogl_scoped_binding_state orig_bindings(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER);
1075 orig_bindings.save_textures();
1077 vogl_scoped_state_saver pixeltransfer_state_saver(cGSTPixelStore);
1079 if (!context_info.is_core_profile())
1080 pixeltransfer_state_saver.save(cGSTPixelTransfer);
1082 vogl_reset_pixel_store_states();
1084 if (!context_info.is_core_profile())
1085 vogl_reset_pixel_transfer_states();
1087 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, 0);
1088 VOGL_CHECK_GL_ERROR;
1090 GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_UNPACK_BUFFER, 0);
1091 VOGL_CHECK_GL_ERROR;
1093 bool created_handle = false;
1097 GLuint handle32 = 0;
1098 GL_ENTRYPOINT(glGenTextures)(1, &handle32);
1099 if ((vogl_check_gl_error()) || (!handle32))
1103 remapper.declare_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle, handle, m_target);
1104 if (!remapper.is_default_remapper())
1106 VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle) == handle);
1109 created_handle = true;
1112 if (m_target == GL_NONE)
1114 // Texture has not been bound to a target yet, so we're done.
1118 uint face = 0, level = 0;
1121 uint tex_width = 0, tex_height = 0, tex_depth = 0, total_actual_levels = 0, num_faces = 0;
1122 int base_level = 0, max_level = 0;
1123 VOGL_NOTE_UNUSED(base_level);
1124 VOGL_NOTE_UNUSED(max_level);
1125 bool is_immutable_format = false, is_compressed = false;
1126 GLenum internal_fmt = GL_NONE;
1128 const ktx_texture &tex0 = m_textures[0];
1130 GL_ENTRYPOINT(glBindTexture)(m_target, static_cast<uint32>(handle));
1131 if (vogl_check_gl_error())
1134 if (m_target == GL_TEXTURE_BUFFER)
1138 GLuint buffer_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_buffer));
1141 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);
1145 internal_fmt = m_params.get_value<int>(GL_TEXTURE_INTERNAL_FORMAT);
1149 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);
1153 GL_ENTRYPOINT(glTexBuffer)(m_target, internal_fmt, buffer_handle);
1154 VOGL_CHECK_GL_ERROR;
1161 any_failures = false;
1163 #define SET_INT(pname) \
1166 if (!set_tex_parameter(pname)) \
1167 any_failures = true; \
1169 #define SET_FLOAT(pname) \
1172 if (!set_tex_parameter(pname)) \
1173 any_failures = true; \
1175 SET_INT(GL_TEXTURE_BASE_LEVEL);
1176 SET_INT(GL_TEXTURE_MAX_LEVEL);
1177 SET_FLOAT(GL_TEXTURE_BORDER_COLOR);
1178 SET_INT(GL_TEXTURE_COMPARE_MODE);
1179 SET_INT(GL_TEXTURE_COMPARE_FUNC);
1180 SET_INT(GL_TEXTURE_MIN_FILTER);
1181 SET_INT(GL_TEXTURE_MAG_FILTER);
1182 if (m_target != GL_TEXTURE_RECTANGLE)
1184 SET_FLOAT(GL_TEXTURE_LOD_BIAS);
1185 SET_FLOAT(GL_TEXTURE_MIN_LOD);
1186 SET_FLOAT(GL_TEXTURE_MAX_LOD);
1188 SET_INT(GL_TEXTURE_SWIZZLE_RGBA);
1189 SET_INT(GL_TEXTURE_WRAP_S);
1190 SET_INT(GL_TEXTURE_WRAP_T);
1191 SET_INT(GL_TEXTURE_WRAP_R);
1193 if (context_info.supports_extension("GL_EXT_texture_filter_anisotropic"))
1195 SET_FLOAT(GL_TEXTURE_MAX_ANISOTROPY_EXT);
1198 if (context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
1200 SET_INT(GL_TEXTURE_SRGB_DECODE_EXT);
1203 if (!context_info.is_core_profile() && context_info.supports_extension("GL_ARB_shadow_ambient"))
1205 SET_FLOAT(GL_TEXTURE_COMPARE_FAIL_VALUE_ARB);
1208 if (!context_info.is_core_profile())
1210 SET_INT(GL_DEPTH_TEXTURE_MODE);
1214 // GL_TEXTURE_PRIORITY
1215 // GL_TEXTURE_RESIDENT
1217 if ((m_is_unquerable) || (!m_textures[0].is_valid()))
1219 if (m_params.get_value<int>(GL_GENERATE_MIPMAP))
1221 GL_ENTRYPOINT(glGenerateMipmap)(m_target);
1227 if (m_num_samples < 1)
1230 tex_width = tex0.get_width();
1231 tex_height = tex0.get_height();
1232 tex_depth = tex0.get_depth();
1233 total_actual_levels = tex0.get_num_mips();
1234 base_level = m_params.get_value<int>(GL_TEXTURE_BASE_LEVEL);
1235 max_level = m_params.get_value<int>(GL_TEXTURE_MAX_LEVEL);
1237 is_immutable_format = m_params.get_value<int>(GL_TEXTURE_IMMUTABLE_FORMAT) != 0;
1238 is_compressed = tex0.is_compressed();
1239 internal_fmt = tex0.get_ogl_internal_fmt();
1241 num_faces = (m_target == GL_TEXTURE_CUBE_MAP) ? cCubeMapFaces : 1;
1244 for (uint sample_index = 1; sample_index < m_num_samples; sample_index++)
1246 const ktx_texture &cmp_tex = m_textures[sample_index];
1248 if ( (!cmp_tex.is_valid()) || (tex_width != cmp_tex.get_width()) || (tex_height != cmp_tex.get_height()) || (tex_depth != cmp_tex.get_depth()) ||
1249 (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()) ||
1250 (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()) )
1252 vogl_error_printf("%s: MSAA consistency error\n", VOGL_METHOD_NAME);
1259 // TODO: Support immutable textures, incomplete textures, etc. Lots more to do here.
1260 if (is_immutable_format)
1262 vogl_warning_printf("%s: TODO: Support immutable textures\n", VOGL_METHOD_NAME);
1265 for (face = 0; face < num_faces; face++)
1267 for (level = 0; level < total_actual_levels; level++)
1269 const vogl_state_vector &level_params = m_level_params[face][level];
1271 if (!level_params.find(GL_TEXTURE_WIDTH))
1274 int level_width = level_params.get_value<int>(GL_TEXTURE_WIDTH);
1275 int level_height = level_params.get_value<int>(GL_TEXTURE_HEIGHT);
1276 int level_depth = level_params.get_value<int>(GL_TEXTURE_DEPTH);
1277 int level_samples = level_params.get_value<int>(GL_TEXTURE_SAMPLES);
1279 GLenum level_internal_fmt = level_params.get_value<int>(GL_TEXTURE_INTERNAL_FORMAT);
1281 if ((level_width < 1) || (level_height < 1) || (level_depth < 1) || (level_internal_fmt != internal_fmt))
1283 vogl_error_printf("%s: Consistency error\n", VOGL_METHOD_NAME);
1288 if ((m_target == GL_TEXTURE_2D_MULTISAMPLE) || (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
1290 if ((is_compressed) || (level_samples != static_cast<int>(m_num_samples)) || (level != 0))
1292 vogl_error_printf("%s: Multisampled texture consistency error\n", VOGL_METHOD_NAME);
1297 if (m_target == GL_TEXTURE_2D_MULTISAMPLE)
1299 GL_ENTRYPOINT(glTexImage2DMultisample)(m_target, m_num_samples, internal_fmt, level_width, level_height, level_params.get_value<GLenum>(GL_TEXTURE_FIXED_SAMPLE_LOCATIONS));
1300 VOGL_CHECK_GL_ERROR;
1302 else if (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
1304 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));
1305 VOGL_CHECK_GL_ERROR;
1309 vogl_error_printf("%s: Unexpected target error\n", VOGL_METHOD_NAME);
1314 // Note: This changes the active GL context to a work context!
1315 if (!splitter.init())
1317 vogl_error_printf("%s: Failed initializing texture splitter object!\n", VOGL_METHOD_NAME);
1322 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
1324 const uint8_vec &src_img = m_textures[sample_index].get_image_data(level, 0, face, 0);
1325 VOGL_ASSERT(src_img.size());
1327 GLuint src_texture = 0;
1328 GL_ENTRYPOINT(glGenTextures)(1, &src_texture);
1329 VOGL_CHECK_GL_ERROR;
1331 const GLenum src_target = (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
1333 GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
1334 VOGL_CHECK_GL_ERROR;
1336 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAX_LEVEL, 0);
1337 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1338 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1339 VOGL_CHECK_GL_ERROR;
1341 if (src_target == GL_TEXTURE_2D_ARRAY)
1343 uint array_size = tex0.get_array_size();
1346 temp_img.reserve(src_img.size() * array_size);
1348 for (uint array_index = 0; array_index < array_size; array_index++)
1350 temp_img.append(m_textures[sample_index].get_image_data(level, array_index, face, 0));
1353 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());
1354 VOGL_CHECK_GL_ERROR;
1358 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());
1359 VOGL_CHECK_GL_ERROR;
1362 bool status = splitter.combine(src_texture, sample_index, m_target, static_cast<uint32>(handle));
1364 GL_ENTRYPOINT(glBindTexture)(src_target, 0);
1365 VOGL_CHECK_GL_ERROR;
1367 GL_ENTRYPOINT(glDeleteTextures)(1, &src_texture);
1368 VOGL_CHECK_GL_ERROR;
1377 // Check if dest texture has stencil
1378 bool has_stencil = utils::is_in_set<GLenum, GLenum>(internal_fmt, GL_DEPTH_STENCIL, GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8_NV);
1379 bool is_reversed_fmt = utils::is_in_set<GLenum, GLenum>(internal_fmt, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8_NV);
1383 GLenum temp_color_format = GL_RGBA;
1384 GLenum temp_color_type = is_reversed_fmt ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_INT_8_8_8_8_REV;
1386 GLuint temp_color_texture = 0;
1387 GL_ENTRYPOINT(glGenTextures)(1, &temp_color_texture);
1388 VOGL_CHECK_GL_ERROR;
1390 const GLenum src_target = (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
1392 GL_ENTRYPOINT(glBindTexture)(src_target, temp_color_texture);
1393 VOGL_CHECK_GL_ERROR;
1395 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAX_LEVEL, 0);
1396 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1397 GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1398 VOGL_CHECK_GL_ERROR;
1400 if (src_target == GL_TEXTURE_2D_ARRAY)
1402 uint array_size = tex0.get_array_size();
1405 temp_img.reserve(src_img.size() * array_size);
1407 for (uint array_index = 0; array_index < array_size; array_index++)
1409 temp_img.append(m_textures[sample_index].get_image_data(level, array_index, face, 0));
1412 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());
1413 VOGL_CHECK_GL_ERROR;
1417 GL_ENTRYPOINT(glTexImage2D)(src_target, level, GL_RGBA, level_width, level_height, 0, temp_color_format, temp_color_type, src_img.get_ptr());
1418 VOGL_CHECK_GL_ERROR;
1421 bool status = splitter.copy_color_sample_to_stencil(temp_color_texture, sample_index, m_target, static_cast<uint32>(handle));
1423 GL_ENTRYPOINT(glBindTexture)(src_target, 0);
1424 VOGL_CHECK_GL_ERROR;
1426 GL_ENTRYPOINT(glDeleteTextures)(1, &temp_color_texture);
1427 VOGL_CHECK_GL_ERROR;
1433 vogl_error_printf("%s: Failed copying MSAA stencil samples from temp color texture to stencil", VOGL_METHOD_NAME);
1444 GLenum target_to_set = m_target;
1445 if (m_target == GL_TEXTURE_CUBE_MAP)
1446 target_to_set = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
1448 if (level_samples > 1)
1450 vogl_error_printf("%s: GL_TEXTURE_SAMPLES consistency error\n", VOGL_METHOD_NAME);
1455 const uint8_vec &src_img = tex0.get_image_data(level, 0, face, 0);
1456 VOGL_ASSERT(src_img.size());
1464 GL_ENTRYPOINT(glCompressedTexImage1D)(target_to_set, level, level_internal_fmt, level_width, 0, src_img.size(), src_img.get_ptr());
1468 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());
1474 case GL_TEXTURE_RECTANGLE:
1475 case GL_TEXTURE_CUBE_MAP:
1476 case GL_TEXTURE_1D_ARRAY:
1478 if (m_target == GL_TEXTURE_1D_ARRAY)
1480 uint array_size = tex0.get_array_size();
1481 for (uint array_index = 0; array_index < array_size; array_index++)
1483 temp_img.append(tex0.get_image_data(level, array_index, face, 0));
1485 level_height = array_size;
1494 GL_ENTRYPOINT(glCompressedTexImage2D)(target_to_set, level, level_internal_fmt, level_width, level_height, 0, src_img.size(), temp_img.get_ptr());
1498 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());
1503 case GL_TEXTURE_2D_ARRAY:
1507 temp_img.reserve(src_img.size() * level_depth);
1509 if (m_target == GL_TEXTURE_3D)
1511 for (int zslice = 0; zslice < level_depth; zslice++)
1513 temp_img.append(tex0.get_image_data(level, 0, face, zslice));
1519 uint array_size = tex0.get_array_size();
1520 for (uint array_index = 0; array_index < array_size; array_index++)
1522 temp_img.append(tex0.get_image_data(level, array_index, face, 0));
1524 level_depth = array_size;
1529 GL_ENTRYPOINT(glCompressedTexImage3D)(target_to_set, level, level_internal_fmt, level_width, level_height, level_depth, 0, temp_img.size(), temp_img.get_ptr());
1533 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());
1541 vogl_error_printf("%s: Unsupported target type %d\n", VOGL_METHOD_NAME, m_target);
1546 if (vogl_check_gl_error())
1548 vogl_error_printf("%s: Failed creating texture image\n", VOGL_METHOD_NAME);
1556 if (m_params.get_value<int>(GL_GENERATE_MIPMAP))
1558 GL_ENTRYPOINT(glGenerateMipmap)(m_target);
1559 vogl_debug_printf("%s: Generating mipmaps for texture, snapshot handle %u GL handle %u\n", VOGL_METHOD_NAME, m_snapshot_handle, (uint)handle);
1567 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,
1568 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));
1574 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,
1575 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));
1577 GL_ENTRYPOINT(glBindTexture)(m_target, 0);
1578 VOGL_CHECK_GL_ERROR;
1582 remapper.delete_handle_and_object(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle, handle);
1590 bool vogl_texture_state::remap_handles(vogl_handle_remapper &remapper)
1597 m_snapshot_handle = static_cast<uint32>(remapper.remap_handle(VOGL_NAMESPACE_TEXTURES, m_snapshot_handle));
1601 m_buffer = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_buffer));
1607 void vogl_texture_state::clear()
1611 m_snapshot_handle = 0;
1617 for (uint i = 0; i < cMaxSamples; i++)
1618 m_textures[i].clear();
1621 for (uint i = 0; i < VOGL_ARRAY_SIZE(m_level_params); i++)
1622 m_level_params[i].clear();
1624 m_is_unquerable = false;
1628 bool vogl_texture_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
1635 node.add_key_value("version", VOGL_SERIALIZED_TEXTURE_STATE_VERSION);
1636 node.add_key_value("handle", m_snapshot_handle);
1637 node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
1638 node.add_key_value("is_unquerable", m_is_unquerable);
1639 node.add_key_value("buffer", m_buffer);
1640 node.add_key_value("samples", m_num_samples);
1642 if ((!m_is_unquerable) && (m_target != GL_NONE))
1644 json_node &tex_params_obj = node.add_object("tex_params");
1645 if (!m_params.serialize(tex_params_obj, blob_manager))
1648 if ((m_target != GL_TEXTURE_BUFFER) && (m_num_samples))
1650 json_node &textures_array_node = node.add_array("textures");
1652 for (uint sample_index = 0; sample_index < m_num_samples; sample_index++)
1654 json_node &texture_node = textures_array_node.add_object();
1656 const ktx_texture &tex = m_textures[sample_index];
1658 const char *pTex_type = utils::map_value(static_cast<int>(m_target), "tex",
1659 GL_TEXTURE_1D, "tex_1d",
1660 GL_TEXTURE_2D, "tex_2d",
1661 GL_TEXTURE_3D, "tex_3d",
1662 GL_TEXTURE_CUBE_MAP, "tex_cube",
1663 GL_TEXTURE_RECTANGLE, "tex_rect",
1664 GL_TEXTURE_2D_ARRAY, "tex_2d_array",
1665 GL_TEXTURE_1D_ARRAY, "tex_1d_array",
1666 GL_TEXTURE_BUFFER, "tex_buffer",
1667 GL_TEXTURE_2D_MULTISAMPLE, "tex_2d_multisample",
1668 GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "tex_2d_multisample_array",
1669 GL_TEXTURE_CUBE_MAP_ARRAY, "tex_cube_array");
1671 uint actual_mip_levels = m_params.get_value<GLint>(GL_TEXTURE_MAX_LEVEL) + 1;
1673 actual_mip_levels = math::minimum(actual_mip_levels, tex.get_num_mips());
1675 dynamic_string prefix;
1679 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()));
1681 case GL_TEXTURE_RECTANGLE:
1683 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()));
1686 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()));
1688 case GL_TEXTURE_1D_ARRAY:
1689 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()));
1691 case GL_TEXTURE_2D_ARRAY:
1692 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()));
1694 case GL_TEXTURE_2D_MULTISAMPLE:
1695 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()));
1697 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1698 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()));
1700 case GL_TEXTURE_CUBE_MAP:
1701 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()));
1703 case GL_TEXTURE_CUBE_MAP_ARRAY:
1704 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()));
1711 dynamic_stream dyn_stream;
1712 data_stream_serializer serializer(dyn_stream);
1713 if (!tex.write_to_stream(serializer))
1716 dyn_stream.seek(0, false);
1718 dynamic_string blob_id(blob_manager.add_stream_compute_unique_id(dyn_stream, prefix.get_ptr(), "ktx"));
1719 if (blob_id.is_empty())
1724 texture_node.add_key_value("texture_data_blob_id", blob_id);
1727 json_node &level_params_array = node.add_array("level_params");
1728 for (uint face = 0; face < m_textures[0].get_num_faces(); face++)
1730 for (uint level = 0; level < m_textures[0].get_num_mips(); level++)
1732 json_node &level_param_array_value = level_params_array.add_object();
1733 if (m_target == GL_TEXTURE_CUBE_MAP)
1734 level_param_array_value.add_key_value("face", face);
1735 level_param_array_value.add_key_value("level", level);
1737 json_node ¶ms_node = level_param_array_value.add_object("params");
1738 if (!m_level_params[face][level].serialize(params_node, blob_manager))
1748 bool vogl_texture_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
1754 if ((!node.has_key("handle")) || (!node.has_key("target")))
1757 m_snapshot_handle = node.value_as_uint32("handle");
1758 m_target = vogl_get_json_value_as_enum(node, "target");
1759 m_is_unquerable = node.value_as_bool("is_unquerable");
1760 m_buffer = node.value_as_uint32("buffer");
1761 m_num_samples = node.value_as_uint32("samples", 1);
1764 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,
1765 GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BUFFER, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
1770 const json_node *pTex_params_obj = node.find_child_object("tex_params");
1771 if (pTex_params_obj)
1773 if (!m_params.deserialize(*pTex_params_obj, blob_manager))
1777 if ((!m_is_unquerable) && (m_target != GL_NONE) && (m_target != GL_TEXTURE_BUFFER))
1779 if (node.has_key("texture_data_blob_id"))
1781 if (m_num_samples != 1)
1784 dynamic_string blob_id(node.value_as_string_ptr("texture_data_blob_id"));
1785 if (blob_id.is_empty())
1788 dynamic_stream tex_data;
1789 if (!blob_manager.get(blob_id, tex_data.get_buf()))
1792 data_stream_serializer serializer(&tex_data);
1793 if (!m_textures[0].read_from_stream(serializer))
1796 else if (node.has_array("textures"))
1798 const json_node *pTextures_array_node = node.find_child_array("textures");
1799 if ((!pTextures_array_node) || (!pTextures_array_node->size()) || (pTextures_array_node->size() > cMaxSamples))
1802 for (uint i = 0; i < pTextures_array_node->size(); i++)
1804 const json_node *pTexture_node = pTextures_array_node->get_child(i);
1808 dynamic_string blob_id(pTexture_node->value_as_string_ptr("texture_data_blob_id"));
1809 if (blob_id.is_empty())
1812 dynamic_stream tex_data;
1813 if (!blob_manager.get(blob_id, tex_data.get_buf()))
1816 data_stream_serializer serializer(&tex_data);
1817 if (!m_textures[i].read_from_stream(serializer))
1826 const json_node *pLevel_params_array = node.find_child_array("level_params");
1827 if (pLevel_params_array)
1829 for (uint i = 0; i < pLevel_params_array->size(); i++)
1831 const json_node *pLevel_params_node = pLevel_params_array->get_value_as_object(i);
1832 if (!pLevel_params_node)
1835 uint face = pLevel_params_node->value_as_uint32("face");
1838 if ((m_target != GL_TEXTURE_CUBE_MAP) || (face > cCubeMapFaces))
1842 uint level = pLevel_params_node->value_as_uint32("level");
1843 // obviously crazy level
1847 if (level >= m_level_params[face].size())
1848 m_level_params[face].resize(level + 1);
1850 const json_node *pParams_node = pLevel_params_node->find_child_object("params");
1854 if (!m_level_params[face][level].deserialize(*pParams_node, blob_manager))
1867 bool vogl_texture_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
1871 if ((!m_is_valid) || (!rhs_obj.is_valid()))
1874 if (rhs_obj.get_type() != cGLSTTexture)
1877 const vogl_texture_state &rhs = static_cast<const vogl_texture_state &>(rhs_obj);
1885 CMP(m_is_unquerable);
1890 for (uint i = 0; i < cCubeMapFaces; i++)
1891 CMP(m_level_params[i]);
1895 for (uint i = 0; i < m_num_samples; i++)
1897 if (m_textures[i].is_valid() != rhs.m_textures[i].is_valid())
1899 if (m_textures[i] != rhs.m_textures[i])