From f588a21e058bcb3bf36be1555c5d159162add86b Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 12 Sep 2016 11:50:24 +0200 Subject: [PATCH] Handle initial states of views better (don't try and copy data contents) --- renderdoc/driver/gl/gl_driver.h | 3 +- renderdoc/driver/gl/gl_manager.cpp | 776 +++++++++--------- .../driver/gl/wrappers/gl_texture_funcs.cpp | 21 +- 3 files changed, 404 insertions(+), 396 deletions(-) diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index b19eb9a1a..bdae966a1 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -243,6 +243,7 @@ private: : curType(eGL_NONE), dimension(0), emulated(false), + view(false), width(0), height(0), depth(0), @@ -256,7 +257,7 @@ private: GLResource resource; GLenum curType; GLint dimension; - bool emulated; + bool emulated, view; GLint width, height, depth, samples; uint32_t creationFlags; GLenum internalFormat; diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index f7ba3a651..242ada979 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -617,241 +617,240 @@ void GLResourceManager::PrepareTextureInitialContents(ResourceId liveid, Resourc state->wrap[2] = eGL_CLAMP_TO_EDGE; } + // we only copy contents for non-views GLuint tex = 0; + if(!details.view) { - GLuint oldtex = 0; - gl.glGetIntegerv(binding, (GLint *)&oldtex); - - gl.glGenTextures(1, &tex); - gl.glBindTexture(details.curType, tex); - - gl.glBindTexture(details.curType, oldtex); - } - - int depth = details.depth; - if(details.curType != eGL_TEXTURE_3D) - depth = 1; - - int mips = - GetNumMips(gl, details.curType, res.name, details.width, details.height, details.depth); - - // create texture of identical format/size to store initial contents - if(details.curType == eGL_TEXTURE_2D_MULTISAMPLE) - { - gl.glTextureStorage2DMultisampleEXT(tex, details.curType, details.samples, - details.internalFormat, details.width, details.height, - GL_TRUE); - mips = 1; - } - else if(details.curType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) - { - gl.glTextureStorage3DMultisampleEXT(tex, details.curType, details.samples, - details.internalFormat, details.width, details.height, - details.depth, GL_TRUE); - mips = 1; - } - else if(details.dimension == 1) - { - gl.glTextureStorage1DEXT(tex, details.curType, mips, details.internalFormat, details.width); - } - else if(details.dimension == 2) - { - gl.glTextureStorage2DEXT(tex, details.curType, mips, details.internalFormat, details.width, - details.height); - } - else if(details.dimension == 3) - { - gl.glTextureStorage3DEXT(tex, details.curType, mips, details.internalFormat, details.width, - details.height, details.depth); - } - - // we need to set maxlevel appropriately for number of mips to force the texture to be complete. - // This can happen if e.g. a texture is initialised just by default with glTexImage for level 0 - // and - // used as a framebuffer attachment, then the implementation is fine with it. Unfortunately - // glCopyImageSubData - // requires completeness across all mips, a stricter requirement :(. - // We set max_level to mips - 1 (so mips=1 means MAX_LEVEL=0). Then restore it to the 'real' - // value we fetched above - int maxlevel = mips - 1; - gl.glTextureParameterivEXT(res.name, details.curType, eGL_TEXTURE_MAX_LEVEL, (GLint *)&maxlevel); - - bool iscomp = IsCompressedFormat(details.internalFormat); - - bool avoidCopySubImage = false; - if(iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips]) - avoidCopySubImage = true; - if(iscomp && details.curType == eGL_TEXTURE_CUBE_MAP && - VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps]) - avoidCopySubImage = true; - - GLint packParams[8] = {0}; - GLint unpackParams[8] = {0}; - GLuint pixelPackBuffer = 0; - GLuint pixelUnpackBuffer = 0; - if(avoidCopySubImage) - { - gl.glGetIntegerv(eGL_PACK_SWAP_BYTES, &packParams[0]); - gl.glGetIntegerv(eGL_PACK_LSB_FIRST, &packParams[1]); - gl.glGetIntegerv(eGL_PACK_ROW_LENGTH, &packParams[2]); - gl.glGetIntegerv(eGL_PACK_IMAGE_HEIGHT, &packParams[3]); - gl.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &packParams[4]); - gl.glGetIntegerv(eGL_PACK_SKIP_ROWS, &packParams[5]); - gl.glGetIntegerv(eGL_PACK_SKIP_IMAGES, &packParams[6]); - gl.glGetIntegerv(eGL_PACK_ALIGNMENT, &packParams[7]); - - gl.glPixelStorei(eGL_PACK_SWAP_BYTES, 0); - gl.glPixelStorei(eGL_PACK_LSB_FIRST, 0); - gl.glPixelStorei(eGL_PACK_ROW_LENGTH, 0); - gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, 0); - gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0); - gl.glPixelStorei(eGL_PACK_SKIP_ROWS, 0); - gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, 0); - gl.glPixelStorei(eGL_PACK_ALIGNMENT, 1); - - gl.glGetIntegerv(eGL_UNPACK_SWAP_BYTES, &unpackParams[0]); - gl.glGetIntegerv(eGL_UNPACK_LSB_FIRST, &unpackParams[1]); - gl.glGetIntegerv(eGL_UNPACK_ROW_LENGTH, &unpackParams[2]); - gl.glGetIntegerv(eGL_UNPACK_IMAGE_HEIGHT, &unpackParams[3]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_PIXELS, &unpackParams[4]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_ROWS, &unpackParams[5]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_IMAGES, &unpackParams[6]); - gl.glGetIntegerv(eGL_UNPACK_ALIGNMENT, &unpackParams[7]); - - gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, 0); - gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, 0); - gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, 0); - gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, 0); - gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, 1); - - gl.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&pixelPackBuffer); - gl.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pixelUnpackBuffer); - gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); - gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); - } - - // copy over mips - for(int i = 0; i < mips; i++) - { - int w = RDCMAX(details.width >> i, 1); - int h = RDCMAX(details.height >> i, 1); - int d = RDCMAX(details.depth >> i, 1); - - if(details.curType == eGL_TEXTURE_CUBE_MAP) - d *= 6; - else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY || - details.curType == eGL_TEXTURE_1D_ARRAY || details.curType == eGL_TEXTURE_2D_ARRAY) - d = details.depth; - - // AMD throws an error copying mips that are smaller than the block size in one dimension, so - // do copy via - // CPU instead (will be slow, potentially we could optimise this if there's a different - // GPU-side image copy - // routine that works on these dimensions. Hopefully there'll only be a couple of such mips). - // - // AMD also has issues copying cubemaps - if((iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) || - (iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] && - details.curType == eGL_TEXTURE_CUBE_MAP)) { - GLenum targets[] = { - eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, - eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - }; + GLuint oldtex = 0; + gl.glGetIntegerv(binding, (GLint *)&oldtex); - int count = ARRAY_COUNT(targets); + gl.glGenTextures(1, &tex); + gl.glBindTexture(details.curType, tex); - if(details.curType != eGL_TEXTURE_CUBE_MAP) - { - targets[0] = details.curType; - count = 1; - } - - for(int trg = 0; trg < count; trg++) - { - GLint compSize; - gl.glGetTextureLevelParameterivEXT(res.name, targets[trg], i, - eGL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compSize); - - size_t size = compSize; - - // sometimes cubemaps return the compressed image size for the whole texture, but we read - // it - // face by face - if(VendorCheck[VendorCheck_EXT_compressed_cube_size] && - details.curType == eGL_TEXTURE_CUBE_MAP) - size /= 6; - - byte *buf = new byte[size]; - - // read to CPU - gl.glGetCompressedTextureImageEXT(res.name, targets[trg], i, buf); - - // write to GPU - if(details.dimension == 1) - gl.glCompressedTextureSubImage1DEXT(tex, targets[trg], i, 0, w, details.internalFormat, - (GLsizei)size, buf); - else if(details.dimension == 2) - gl.glCompressedTextureSubImage2DEXT(tex, targets[trg], i, 0, 0, w, h, - details.internalFormat, (GLsizei)size, buf); - else if(details.dimension == 3) - gl.glCompressedTextureSubImage3DEXT(tex, targets[trg], i, 0, 0, 0, w, h, d, - details.internalFormat, (GLsizei)size, buf); - - delete[] buf; - } + gl.glBindTexture(details.curType, oldtex); } - else + + int depth = details.depth; + if(details.curType != eGL_TEXTURE_3D) + depth = 1; + + int mips = + GetNumMips(gl, details.curType, res.name, details.width, details.height, details.depth); + + // create texture of identical format/size to store initial contents + if(details.curType == eGL_TEXTURE_2D_MULTISAMPLE) { - // it seems like everything explodes if I do glCopyImageSubData on a D32F_S8 texture - - // in-program the overlay - // gets corrupted as one UBO seems to not provide data anymore until it's "refreshed". It - // seems like a driver bug, - // nvidia specific. - // In most cases a program isn't going to rely on the contents of a depth-stencil buffer - // (shadow maps that it might - // require would be depth-only formatted). - if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && - VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) - RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); + gl.glTextureStorage2DMultisampleEXT(tex, details.curType, details.samples, + details.internalFormat, details.width, details.height, + GL_TRUE); + mips = 1; + } + else if(details.curType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + gl.glTextureStorage3DMultisampleEXT(tex, details.curType, details.samples, + details.internalFormat, details.width, details.height, + details.depth, GL_TRUE); + mips = 1; + } + else if(details.dimension == 1) + { + gl.glTextureStorage1DEXT(tex, details.curType, mips, details.internalFormat, details.width); + } + else if(details.dimension == 2) + { + gl.glTextureStorage2DEXT(tex, details.curType, mips, details.internalFormat, details.width, + details.height); + } + else if(details.dimension == 3) + { + gl.glTextureStorage3DEXT(tex, details.curType, mips, details.internalFormat, details.width, + details.height, details.depth); + } + + // we need to set maxlevel appropriately for number of mips to force the texture to be + // complete. + // This can happen if e.g. a texture is initialised just by default with glTexImage for level + // 0 and used as a framebuffer attachment, then the implementation is fine with it. + // Unfortunately glCopyImageSubData requires completeness across all mips, a stricter + // requirement :(. + // We set max_level to mips - 1 (so mips=1 means MAX_LEVEL=0). Then restore it to the 'real' + // value we fetched above + int maxlevel = mips - 1; + gl.glTextureParameterivEXT(res.name, details.curType, eGL_TEXTURE_MAX_LEVEL, + (GLint *)&maxlevel); + + bool iscomp = IsCompressedFormat(details.internalFormat); + + bool avoidCopySubImage = false; + if(iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips]) + avoidCopySubImage = true; + if(iscomp && details.curType == eGL_TEXTURE_CUBE_MAP && + VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps]) + avoidCopySubImage = true; + + GLint packParams[8] = {0}; + GLint unpackParams[8] = {0}; + GLuint pixelPackBuffer = 0; + GLuint pixelUnpackBuffer = 0; + if(avoidCopySubImage) + { + gl.glGetIntegerv(eGL_PACK_SWAP_BYTES, &packParams[0]); + gl.glGetIntegerv(eGL_PACK_LSB_FIRST, &packParams[1]); + gl.glGetIntegerv(eGL_PACK_ROW_LENGTH, &packParams[2]); + gl.glGetIntegerv(eGL_PACK_IMAGE_HEIGHT, &packParams[3]); + gl.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &packParams[4]); + gl.glGetIntegerv(eGL_PACK_SKIP_ROWS, &packParams[5]); + gl.glGetIntegerv(eGL_PACK_SKIP_IMAGES, &packParams[6]); + gl.glGetIntegerv(eGL_PACK_ALIGNMENT, &packParams[7]); + + gl.glPixelStorei(eGL_PACK_SWAP_BYTES, 0); + gl.glPixelStorei(eGL_PACK_LSB_FIRST, 0); + gl.glPixelStorei(eGL_PACK_ROW_LENGTH, 0); + gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, 0); + gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0); + gl.glPixelStorei(eGL_PACK_SKIP_ROWS, 0); + gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, 0); + gl.glPixelStorei(eGL_PACK_ALIGNMENT, 1); + + gl.glGetIntegerv(eGL_UNPACK_SWAP_BYTES, &unpackParams[0]); + gl.glGetIntegerv(eGL_UNPACK_LSB_FIRST, &unpackParams[1]); + gl.glGetIntegerv(eGL_UNPACK_ROW_LENGTH, &unpackParams[2]); + gl.glGetIntegerv(eGL_UNPACK_IMAGE_HEIGHT, &unpackParams[3]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_PIXELS, &unpackParams[4]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_ROWS, &unpackParams[5]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_IMAGES, &unpackParams[6]); + gl.glGetIntegerv(eGL_UNPACK_ALIGNMENT, &unpackParams[7]); + + gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, 0); + gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, 0); + gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, 0); + gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, 1); + + gl.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&pixelPackBuffer); + gl.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pixelUnpackBuffer); + gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); + gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); + } + + // copy over mips + for(int i = 0; i < mips; i++) + { + int w = RDCMAX(details.width >> i, 1); + int h = RDCMAX(details.height >> i, 1); + int d = RDCMAX(details.depth >> i, 1); + + if(details.curType == eGL_TEXTURE_CUBE_MAP) + d *= 6; + else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY || + details.curType == eGL_TEXTURE_1D_ARRAY || details.curType == eGL_TEXTURE_2D_ARRAY) + d = details.depth; + + // AMD throws an error copying mips that are smaller than the block size in one dimension, + // so do copy via CPU instead (will be slow, potentially we could optimise this if there's a + // different GPU-side image copy routine that works on these dimensions. Hopefully there'll + // only be a couple of such mips). + // AMD also has issues copying cubemaps + if((iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) || + (iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] && + details.curType == eGL_TEXTURE_CUBE_MAP)) + { + GLenum targets[] = { + eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + int count = ARRAY_COUNT(targets); + + if(details.curType != eGL_TEXTURE_CUBE_MAP) + { + targets[0] = details.curType; + count = 1; + } + + for(int trg = 0; trg < count; trg++) + { + GLint compSize; + gl.glGetTextureLevelParameterivEXT(res.name, targets[trg], i, + eGL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compSize); + + size_t size = compSize; + + // sometimes cubemaps return the compressed image size for the whole texture, but we + // read it face by face + if(VendorCheck[VendorCheck_EXT_compressed_cube_size] && + details.curType == eGL_TEXTURE_CUBE_MAP) + size /= 6; + + byte *buf = new byte[size]; + + // read to CPU + gl.glGetCompressedTextureImageEXT(res.name, targets[trg], i, buf); + + // write to GPU + if(details.dimension == 1) + gl.glCompressedTextureSubImage1DEXT(tex, targets[trg], i, 0, w, + details.internalFormat, (GLsizei)size, buf); + else if(details.dimension == 2) + gl.glCompressedTextureSubImage2DEXT(tex, targets[trg], i, 0, 0, w, h, + details.internalFormat, (GLsizei)size, buf); + else if(details.dimension == 3) + gl.glCompressedTextureSubImage3DEXT(tex, targets[trg], i, 0, 0, 0, w, h, d, + details.internalFormat, (GLsizei)size, buf); + + delete[] buf; + } + } else - gl.glCopyImageSubData(res.name, details.curType, i, 0, 0, 0, tex, details.curType, i, 0, - 0, 0, w, h, d); + { + // it seems like everything explodes if I do glCopyImageSubData on a D32F_S8 texture - + // in-program the overlay gets corrupted as one UBO seems to not provide data anymore + // until it's "refreshed". It seems like a driver bug, nvidia specific. In most cases a + // program isn't going to rely on the contents of a depth-stencil buffer (shadow maps that + // it might require would be depth-only formatted). + if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && + VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) + RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); + else + gl.glCopyImageSubData(res.name, details.curType, i, 0, 0, 0, tex, details.curType, i, 0, + 0, 0, w, h, d); + } } + + if(avoidCopySubImage) + { + gl.glPixelStorei(eGL_PACK_SWAP_BYTES, packParams[0]); + gl.glPixelStorei(eGL_PACK_LSB_FIRST, packParams[1]); + gl.glPixelStorei(eGL_PACK_ROW_LENGTH, packParams[2]); + gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, packParams[3]); + gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, packParams[4]); + gl.glPixelStorei(eGL_PACK_SKIP_ROWS, packParams[5]); + gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, packParams[6]); + gl.glPixelStorei(eGL_PACK_ALIGNMENT, packParams[7]); + + gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, unpackParams[0]); + gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, unpackParams[1]); + gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, unpackParams[2]); + gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, unpackParams[3]); + gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, unpackParams[4]); + gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, unpackParams[5]); + gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, unpackParams[6]); + gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, unpackParams[7]); + + gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, pixelPackBuffer); + gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pixelUnpackBuffer); + } + + gl.glTextureParameterivEXT(res.name, details.curType, eGL_TEXTURE_MAX_LEVEL, + (GLint *)&state->maxLevel); } - if(avoidCopySubImage) - { - gl.glPixelStorei(eGL_PACK_SWAP_BYTES, packParams[0]); - gl.glPixelStorei(eGL_PACK_LSB_FIRST, packParams[1]); - gl.glPixelStorei(eGL_PACK_ROW_LENGTH, packParams[2]); - gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, packParams[3]); - gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, packParams[4]); - gl.glPixelStorei(eGL_PACK_SKIP_ROWS, packParams[5]); - gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, packParams[6]); - gl.glPixelStorei(eGL_PACK_ALIGNMENT, packParams[7]); - - gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, unpackParams[0]); - gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, unpackParams[1]); - gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, unpackParams[2]); - gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, unpackParams[3]); - gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, unpackParams[4]); - gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, unpackParams[5]); - gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, unpackParams[6]); - gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, unpackParams[7]); - - gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, pixelPackBuffer); - gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pixelUnpackBuffer); - } - - gl.glTextureParameterivEXT(res.name, details.curType, eGL_TEXTURE_MAX_LEVEL, - (GLint *)&state->maxLevel); - SetInitialContents(origid, InitialContentData(TextureRes(res.Context, tex), 0, (byte *)state)); } else @@ -1024,9 +1023,10 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) SERIALISE_ELEMENT(bool, isCompressed, IsCompressedFormat(details.internalFormat)); - if(details.curType == eGL_TEXTURE_BUFFER) + if(details.curType == eGL_TEXTURE_BUFFER || details.view) { // no contents to copy for texture buffer (it's copied under the buffer) + // same applies for texture views, their data is copies under the aliased texture } else if(isCompressed) { @@ -1144,6 +1144,8 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) } else { + WrappedOpenGL::TextureData &details = m_GL->m_Textures[GetLiveID(Id)]; + SERIALISE_ELEMENT(GLenum, internalformat, eGL_NONE); if(internalformat != eGL_NONE) @@ -1274,7 +1276,7 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) GLuint tex = 0; - if(textype != eGL_TEXTURE_BUFFER) + if(textype != eGL_TEXTURE_BUFFER && !details.view) { GLuint prevtex = 0; gl.glGetIntegerv(TextureBinding(textype), (GLint *)&prevtex); @@ -1289,7 +1291,7 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) EmulateLuminanceFormat(gl, tex, textype, internalformat, dummy); // create texture of identical format/size to store initial contents - if(textype == eGL_TEXTURE_BUFFER) + if(textype == eGL_TEXTURE_BUFFER || details.view) { // no 'contents' texture to create } @@ -1318,7 +1320,7 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) gl.glTextureStorage3DEXT(tex, textype, mips, internalformat, width, height, depth); } - if(textype == eGL_TEXTURE_BUFFER) + if(textype == eGL_TEXTURE_BUFFER || details.view) { // no contents to serialise } @@ -1420,7 +1422,7 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) } } - if(textype != eGL_TEXTURE_BUFFER) + if(textype != eGL_TEXTURE_BUFFER && !details.view) SetInitialContents(Id, InitialContentData(TextureRes(m_GL->GetCtx(), tex), 0, (byte *)state)); else @@ -1562,183 +1564,177 @@ void GLResourceManager::Apply_InitialState(GLResource live, InitialContentData i { GLuint tex = initial.resource.name; - int mips = GetNumMips(gl, details.curType, tex, details.width, details.height, details.depth); - - // we need to set maxlevel appropriately for number of mips to force the texture to be - // complete. - // This can happen if e.g. a texture is initialised just by default with glTexImage for level - // 0 and - // used as a framebuffer attachment, then the implementation is fine with it. Unfortunately - // glCopyImageSubData - // requires completeness across all mips, a stricter requirement :(. - // We set max_level to mips - 1 (so mips=1 means MAX_LEVEL=0). Then below where we set the - // texture state, the - // correct MAX_LEVEL is set to whatever the program had. - int maxlevel = mips - 1; - gl.glTextureParameterivEXT(live.name, details.curType, eGL_TEXTURE_MAX_LEVEL, - (GLint *)&maxlevel); - - bool iscomp = IsCompressedFormat(details.internalFormat); - - bool avoidCopySubImage = false; - if(iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips]) - avoidCopySubImage = true; - if(iscomp && details.curType == eGL_TEXTURE_CUBE_MAP && - VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps]) - avoidCopySubImage = true; - - GLint packParams[8]; - GLint unpackParams[8]; - if(avoidCopySubImage) + if(initial.resource != GLResource(MakeNullResource) && tex != 0) { - gl.glGetIntegerv(eGL_PACK_SWAP_BYTES, &packParams[0]); - gl.glGetIntegerv(eGL_PACK_LSB_FIRST, &packParams[1]); - gl.glGetIntegerv(eGL_PACK_ROW_LENGTH, &packParams[2]); - gl.glGetIntegerv(eGL_PACK_IMAGE_HEIGHT, &packParams[3]); - gl.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &packParams[4]); - gl.glGetIntegerv(eGL_PACK_SKIP_ROWS, &packParams[5]); - gl.glGetIntegerv(eGL_PACK_SKIP_IMAGES, &packParams[6]); - gl.glGetIntegerv(eGL_PACK_ALIGNMENT, &packParams[7]); + int mips = GetNumMips(gl, details.curType, tex, details.width, details.height, details.depth); - gl.glPixelStorei(eGL_PACK_SWAP_BYTES, 0); - gl.glPixelStorei(eGL_PACK_LSB_FIRST, 0); - gl.glPixelStorei(eGL_PACK_ROW_LENGTH, 0); - gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, 0); - gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0); - gl.glPixelStorei(eGL_PACK_SKIP_ROWS, 0); - gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, 0); - gl.glPixelStorei(eGL_PACK_ALIGNMENT, 1); + // we need to set maxlevel appropriately for number of mips to force the texture to be + // complete. This can happen if e.g. a texture is initialised just by default with + // glTexImage for level 0 and used as a framebuffer attachment, then the implementation is + // fine with it. + // Unfortunately glCopyImageSubData requires completeness across all mips, a stricter + // requirement :(. + // We set max_level to mips - 1 (so mips=1 means MAX_LEVEL=0). Then below where we set the + // texture state, the correct MAX_LEVEL is set to whatever the program had. + int maxlevel = mips - 1; + gl.glTextureParameterivEXT(live.name, details.curType, eGL_TEXTURE_MAX_LEVEL, + (GLint *)&maxlevel); - gl.glGetIntegerv(eGL_UNPACK_SWAP_BYTES, &unpackParams[0]); - gl.glGetIntegerv(eGL_UNPACK_LSB_FIRST, &unpackParams[1]); - gl.glGetIntegerv(eGL_UNPACK_ROW_LENGTH, &unpackParams[2]); - gl.glGetIntegerv(eGL_UNPACK_IMAGE_HEIGHT, &unpackParams[3]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_PIXELS, &unpackParams[4]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_ROWS, &unpackParams[5]); - gl.glGetIntegerv(eGL_UNPACK_SKIP_IMAGES, &unpackParams[6]); - gl.glGetIntegerv(eGL_UNPACK_ALIGNMENT, &unpackParams[7]); + bool iscomp = IsCompressedFormat(details.internalFormat); - gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, 0); - gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, 0); - gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, 0); - gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, 0); - gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, 0); - gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, 1); - } + bool avoidCopySubImage = false; + if(iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips]) + avoidCopySubImage = true; + if(iscomp && details.curType == eGL_TEXTURE_CUBE_MAP && + VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps]) + avoidCopySubImage = true; - // copy over mips - for(int i = 0; i < mips; i++) - { - int w = RDCMAX(details.width >> i, 1); - int h = RDCMAX(details.height >> i, 1); - int d = RDCMAX(details.depth >> i, 1); - - if(details.curType == eGL_TEXTURE_CUBE_MAP) - d *= 6; - else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY || - details.curType == eGL_TEXTURE_1D_ARRAY || details.curType == eGL_TEXTURE_2D_ARRAY) - d = details.depth; - - // AMD throws an error copying mips that are smaller than the block size in one dimension, - // so do copy via - // CPU instead (will be slow, potentially we could optimise this if there's a different - // GPU-side image copy - // routine that works on these dimensions. Hopefully there'll only be a couple of such - // mips). - // - // AMD also has issues copying cubemaps - if((iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) || - (iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] && - details.curType == eGL_TEXTURE_CUBE_MAP)) + GLint packParams[8]; + GLint unpackParams[8]; + if(avoidCopySubImage) { - GLenum targets[] = { - eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, - eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - }; + gl.glGetIntegerv(eGL_PACK_SWAP_BYTES, &packParams[0]); + gl.glGetIntegerv(eGL_PACK_LSB_FIRST, &packParams[1]); + gl.glGetIntegerv(eGL_PACK_ROW_LENGTH, &packParams[2]); + gl.glGetIntegerv(eGL_PACK_IMAGE_HEIGHT, &packParams[3]); + gl.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &packParams[4]); + gl.glGetIntegerv(eGL_PACK_SKIP_ROWS, &packParams[5]); + gl.glGetIntegerv(eGL_PACK_SKIP_IMAGES, &packParams[6]); + gl.glGetIntegerv(eGL_PACK_ALIGNMENT, &packParams[7]); - int count = ARRAY_COUNT(targets); + gl.glPixelStorei(eGL_PACK_SWAP_BYTES, 0); + gl.glPixelStorei(eGL_PACK_LSB_FIRST, 0); + gl.glPixelStorei(eGL_PACK_ROW_LENGTH, 0); + gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, 0); + gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, 0); + gl.glPixelStorei(eGL_PACK_SKIP_ROWS, 0); + gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, 0); + gl.glPixelStorei(eGL_PACK_ALIGNMENT, 1); - if(details.curType != eGL_TEXTURE_CUBE_MAP) - { - targets[0] = details.curType; - count = 1; - } + gl.glGetIntegerv(eGL_UNPACK_SWAP_BYTES, &unpackParams[0]); + gl.glGetIntegerv(eGL_UNPACK_LSB_FIRST, &unpackParams[1]); + gl.glGetIntegerv(eGL_UNPACK_ROW_LENGTH, &unpackParams[2]); + gl.glGetIntegerv(eGL_UNPACK_IMAGE_HEIGHT, &unpackParams[3]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_PIXELS, &unpackParams[4]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_ROWS, &unpackParams[5]); + gl.glGetIntegerv(eGL_UNPACK_SKIP_IMAGES, &unpackParams[6]); + gl.glGetIntegerv(eGL_UNPACK_ALIGNMENT, &unpackParams[7]); - for(int trg = 0; trg < count; trg++) - { - GLint compSize; - gl.glGetTextureLevelParameterivEXT(tex, targets[trg], i, - eGL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compSize); - - size_t size = compSize; - - // sometimes cubemaps return the compressed image size for the whole texture, but we - // read it - // face by face - if(VendorCheck[VendorCheck_EXT_compressed_cube_size] && - details.curType == eGL_TEXTURE_CUBE_MAP) - size /= 6; - - byte *buf = new byte[size]; - - // read to CPU - gl.glGetCompressedTextureImageEXT(tex, targets[trg], i, buf); - - // write to GPU - if(details.dimension == 1) - gl.glCompressedTextureSubImage1DEXT(live.name, targets[trg], i, 0, w, - details.internalFormat, (GLsizei)size, buf); - else if(details.dimension == 2) - gl.glCompressedTextureSubImage2DEXT(live.name, targets[trg], i, 0, 0, w, h, - details.internalFormat, (GLsizei)size, buf); - else if(details.dimension == 3) - gl.glCompressedTextureSubImage3DEXT(live.name, targets[trg], i, 0, 0, 0, w, h, d, - details.internalFormat, (GLsizei)size, buf); - - delete[] buf; - } + gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, 0); + gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, 0); + gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, 0); + gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, 0); + gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, 1); } - else + + // copy over mips + for(int i = 0; i < mips; i++) { - // it seems like everything explodes if I do glCopyImageSubData on a D32F_S8 texture - on - // replay loads of things - // get heavily corrupted - probably the same as the problems we get in-program, but - // magnified. It seems like a driver bug, - // nvidia specific. - // In most cases a program isn't going to rely on the contents of a depth-stencil buffer - // (shadow maps that it might - // require would be depth-only formatted). - if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && - VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) - RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); + int w = RDCMAX(details.width >> i, 1); + int h = RDCMAX(details.height >> i, 1); + int d = RDCMAX(details.depth >> i, 1); + + if(details.curType == eGL_TEXTURE_CUBE_MAP) + d *= 6; + else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY || + details.curType == eGL_TEXTURE_1D_ARRAY || details.curType == eGL_TEXTURE_2D_ARRAY) + d = details.depth; + + // AMD throws an error copying mips that are smaller than the block size in one dimension, + // so do copy via CPU instead (will be slow, potentially we could optimise this if there's + // a different GPU-side image copy routine that works on these dimensions. Hopefully + // there'll only be a couple of such mips). + // AMD also has issues copying cubemaps + if((iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) || + (iscomp && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] && + details.curType == eGL_TEXTURE_CUBE_MAP)) + { + GLenum targets[] = { + eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + int count = ARRAY_COUNT(targets); + + if(details.curType != eGL_TEXTURE_CUBE_MAP) + { + targets[0] = details.curType; + count = 1; + } + + for(int trg = 0; trg < count; trg++) + { + GLint compSize; + gl.glGetTextureLevelParameterivEXT(tex, targets[trg], i, + eGL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compSize); + + size_t size = compSize; + + // sometimes cubemaps return the compressed image size for the whole texture, but we + // read it face by face + if(VendorCheck[VendorCheck_EXT_compressed_cube_size] && + details.curType == eGL_TEXTURE_CUBE_MAP) + size /= 6; + + byte *buf = new byte[size]; + + // read to CPU + gl.glGetCompressedTextureImageEXT(tex, targets[trg], i, buf); + + // write to GPU + if(details.dimension == 1) + gl.glCompressedTextureSubImage1DEXT(live.name, targets[trg], i, 0, w, + details.internalFormat, (GLsizei)size, buf); + else if(details.dimension == 2) + gl.glCompressedTextureSubImage2DEXT(live.name, targets[trg], i, 0, 0, w, h, + details.internalFormat, (GLsizei)size, buf); + else if(details.dimension == 3) + gl.glCompressedTextureSubImage3DEXT(live.name, targets[trg], i, 0, 0, 0, w, h, d, + details.internalFormat, (GLsizei)size, buf); + + delete[] buf; + } + } else - gl.glCopyImageSubData(tex, details.curType, i, 0, 0, 0, live.name, details.curType, i, - 0, 0, 0, w, h, d); + { + // it seems like everything explodes if I do glCopyImageSubData on a D32F_S8 texture - + // on replay loads of things get heavily corrupted - probably the same as the problems + // we get in-program, but magnified. It seems like a driver bug, nvidia specific. + // In most cases a program isn't going to rely on the contents of a depth-stencil buffer + // (shadow maps that it might require would be depth-only formatted). + if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && + VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) + RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); + else + gl.glCopyImageSubData(tex, details.curType, i, 0, 0, 0, live.name, details.curType, i, + 0, 0, 0, w, h, d); + } } - } - if(avoidCopySubImage) - { - gl.glPixelStorei(eGL_PACK_SWAP_BYTES, packParams[0]); - gl.glPixelStorei(eGL_PACK_LSB_FIRST, packParams[1]); - gl.glPixelStorei(eGL_PACK_ROW_LENGTH, packParams[2]); - gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, packParams[3]); - gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, packParams[4]); - gl.glPixelStorei(eGL_PACK_SKIP_ROWS, packParams[5]); - gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, packParams[6]); - gl.glPixelStorei(eGL_PACK_ALIGNMENT, packParams[7]); + if(avoidCopySubImage) + { + gl.glPixelStorei(eGL_PACK_SWAP_BYTES, packParams[0]); + gl.glPixelStorei(eGL_PACK_LSB_FIRST, packParams[1]); + gl.glPixelStorei(eGL_PACK_ROW_LENGTH, packParams[2]); + gl.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, packParams[3]); + gl.glPixelStorei(eGL_PACK_SKIP_PIXELS, packParams[4]); + gl.glPixelStorei(eGL_PACK_SKIP_ROWS, packParams[5]); + gl.glPixelStorei(eGL_PACK_SKIP_IMAGES, packParams[6]); + gl.glPixelStorei(eGL_PACK_ALIGNMENT, packParams[7]); - gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, unpackParams[0]); - gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, unpackParams[1]); - gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, unpackParams[2]); - gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, unpackParams[3]); - gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, unpackParams[4]); - gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, unpackParams[5]); - gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, unpackParams[6]); - gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, unpackParams[7]); + gl.glPixelStorei(eGL_UNPACK_SWAP_BYTES, unpackParams[0]); + gl.glPixelStorei(eGL_UNPACK_LSB_FIRST, unpackParams[1]); + gl.glPixelStorei(eGL_UNPACK_ROW_LENGTH, unpackParams[2]); + gl.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, unpackParams[3]); + gl.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, unpackParams[4]); + gl.glPixelStorei(eGL_UNPACK_SKIP_ROWS, unpackParams[5]); + gl.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, unpackParams[6]); + gl.glPixelStorei(eGL_UNPACK_ALIGNMENT, unpackParams[7]); + } } bool ms = (details.curType == eGL_TEXTURE_2D_MULTISAMPLE || diff --git a/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp index 6dfb6d403..1a06577d4 100644 --- a/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp @@ -631,6 +631,7 @@ bool WrappedOpenGL::Serialise_glTextureView(GLuint texture, GLenum target, GLuin m_Textures[liveTexId].curType = TextureTarget(Target); m_Textures[liveTexId].internalFormat = InternalFormat; + m_Textures[liveTexId].view = true; m_Textures[liveTexId].width = m_Textures[liveOrigId].width; m_Textures[liveTexId].height = m_Textures[liveOrigId].height; m_Textures[liveTexId].depth = m_Textures[liveOrigId].depth; @@ -664,16 +665,26 @@ void WrappedOpenGL::glTextureView(GLuint texture, GLenum target, GLuint origtext // illegal to re-type textures record->VerifyDataType(target); + + // mark the underlying resource as dirty to avoid tracking dirty across + // aliased resources etc. + if(m_State == WRITING_IDLE) + GetResourceManager()->MarkDirtyResource(origrecord->GetResourceID()); + else + m_MissingTracks.insert(origrecord->GetResourceID()); } - else + { ResourceId texId = GetResourceManager()->GetID(TextureRes(GetCtx(), texture)); - ResourceId origId = GetResourceManager()->GetID(TextureRes(GetCtx(), origtexture)); + ResourceId viewedId = GetResourceManager()->GetID(TextureRes(GetCtx(), origtexture)); m_Textures[texId].internalFormat = internalformat; - m_Textures[texId].width = m_Textures[origId].width; - m_Textures[texId].height = m_Textures[origId].height; - m_Textures[texId].depth = m_Textures[origId].depth; + m_Textures[texId].view = true; + m_Textures[texId].dimension = m_Textures[viewedId].dimension; + m_Textures[texId].width = m_Textures[viewedId].width; + m_Textures[texId].height = m_Textures[viewedId].height; + m_Textures[texId].depth = m_Textures[viewedId].depth; + m_Textures[texId].curType = TextureTarget(target); } }