Handle initial states of views better (don't try and copy data contents)

This commit is contained in:
baldurk
2016-09-12 11:50:24 +02:00
parent 00a81cc065
commit f588a21e05
3 changed files with 404 additions and 396 deletions
+2 -1
View File
@@ -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;
+386 -390
View File
@@ -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 ||
@@ -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);
}
}