Support creating typeless proxy textures in GL. Closes #1516

* Since GL requires a concrete texture format, we create the textures as UINT
  format, and then cast to the right view on display once we know.
* The cast requires a copy - ARB_texture_view isn't always supported and even
  when they are they require immutable textures (ARB_texture_storage) which we
  don't want to require either.
This commit is contained in:
baldurk
2019-10-31 13:38:20 +00:00
parent db563bb0bf
commit 44b2247151
8 changed files with 614 additions and 166 deletions
+12 -12
View File
@@ -2245,7 +2245,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RGBA32F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RGBA32I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGBA32UI;
else
RDCERR("Unrecognised component type");
@@ -2256,7 +2256,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RGBA16F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RGBA16I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGBA16UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RGBA16_SNORM;
@@ -2269,7 +2269,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
{
if(fmt.compType == CompType::SInt)
ret = eGL_RGBA8I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGBA8UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RGBA8_SNORM;
@@ -2295,7 +2295,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RGB32F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RGB32I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGB32UI;
else
RDCERR("Unrecognised component type");
@@ -2306,7 +2306,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RGB16F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RGB16I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGB16UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RGB16_SNORM;
@@ -2319,7 +2319,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
{
if(fmt.compType == CompType::SInt)
ret = eGL_RGB8I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RGB8UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RGB8_SNORM;
@@ -2345,7 +2345,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RG32F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RG32I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RG32UI;
else
RDCERR("Unrecognised component type");
@@ -2356,7 +2356,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_RG16F;
else if(fmt.compType == CompType::SInt)
ret = eGL_RG16I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RG16UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RG16_SNORM;
@@ -2369,7 +2369,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
{
if(fmt.compType == CompType::SInt)
ret = eGL_RG8I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_RG8UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_RG8_SNORM;
@@ -2395,7 +2395,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_R32F;
else if(fmt.compType == CompType::SInt)
ret = eGL_R32I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_R32UI;
else if(fmt.compType == CompType::Depth)
ret = eGL_DEPTH_COMPONENT32F;
@@ -2412,7 +2412,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
ret = eGL_R16F;
else if(fmt.compType == CompType::SInt)
ret = eGL_R16I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_R16UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_R16_SNORM;
@@ -2427,7 +2427,7 @@ GLenum MakeGLFormat(ResourceFormat fmt)
{
if(fmt.compType == CompType::SInt)
ret = eGL_R8I;
else if(fmt.compType == CompType::UInt)
else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless)
ret = eGL_R8UI;
else if(fmt.compType == CompType::SNorm)
ret = eGL_R8_SNORM;
+134
View File
@@ -2715,6 +2715,140 @@ void WrappedOpenGL::QueueResourceRelease(GLResource res)
}
}
void WrappedOpenGL::CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint,
GLenum textype, GLint dim, GLint width, GLint height,
GLint depth, GLint samples, int mips)
{
if(textype == eGL_TEXTURE_BUFFER)
{
return;
}
GLuint ppb = 0, pub = 0;
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb);
GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub);
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0);
if(textype == eGL_TEXTURE_2D_MULTISAMPLE)
{
GL.glTextureStorage2DMultisampleEXT(tex, textype, samples, internalFormat, width, height,
GL_TRUE);
}
else if(textype == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY)
{
GL.glTextureStorage3DMultisampleEXT(tex, textype, samples, internalFormat, width, height, depth,
GL_TRUE);
}
else
{
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAX_LEVEL, mips - 1);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
bool isCompressed = IsCompressedFormat(internalFormat);
GLenum baseFormat = eGL_RGBA;
GLenum dataType = internalFormatHint != eGL_NONE ? internalFormatHint : eGL_UNSIGNED_BYTE;
if(!isCompressed)
{
baseFormat = GetBaseFormat(internalFormat);
if(internalFormatHint == eGL_NONE)
dataType = GetDataType(internalFormat);
}
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(textype != eGL_TEXTURE_CUBE_MAP)
{
targets[0] = textype;
count = 1;
}
GLsizei w = (GLsizei)width;
GLsizei h = (GLsizei)height;
GLsizei d = (GLsizei)depth;
for(int m = 0; m < mips; m++)
{
for(int t = 0; t < count; t++)
{
if(isCompressed)
{
GLsizei compSize = (GLsizei)GetCompressedByteSize(w, h, d, internalFormat);
std::vector<byte> dummy;
dummy.resize(compSize);
if(dim == 1)
GL.glCompressedTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, compSize,
&dummy[0]);
else if(dim == 2)
GL.glCompressedTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, compSize,
&dummy[0]);
else if(dim == 3)
GL.glCompressedTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0,
compSize, &dummy[0]);
}
else
{
if(dim == 1)
GL.glTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, baseFormat, dataType,
NULL);
else if(dim == 2)
GL.glTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, baseFormat,
dataType, NULL);
else if(dim == 3)
GL.glTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, baseFormat,
dataType, NULL);
}
}
w = RDCMAX(1, w >> 1);
if(textype != eGL_TEXTURE_1D_ARRAY)
h = RDCMAX(1, h >> 1);
if(textype != eGL_TEXTURE_2D_ARRAY && textype != eGL_TEXTURE_CUBE_MAP_ARRAY)
d = RDCMAX(1, d >> 1);
}
}
if(IsCaptureMode(m_State))
{
// register this texture and set up its texture details, so it's available for emulation
// readback.
GLResource res = TextureRes(GetCtx(), tex);
ResourceId id = GetResourceManager()->RegisterResource(res);
WrappedOpenGL::TextureData &details = m_Textures[id];
details.resource = res;
details.curType = textype;
details.dimension = dim;
details.emulated = details.view = false;
details.width = width;
details.height = height;
details.depth = depth;
details.samples = samples;
details.creationFlags = TextureCategory::NoFlags;
details.internalFormat = internalFormat;
details.mipsValid = (1 << mips) - 1;
}
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub);
}
void WrappedOpenGL::ReleaseResource(GLResource res)
{
switch(res.Namespace)
+4
View File
@@ -552,6 +552,10 @@ public:
ContextPair &GetCtx();
GLResourceRecord *GetContextRecord();
void CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint,
GLenum textype, GLint dim, GLint width, GLint height, GLint depth,
GLint samples, int mips);
void PushInternalShader() { m_InternalShader++; }
void PopInternalShader() { m_InternalShader--; }
bool IsInternalShader() { return m_InternalShader > 0; }
+7 -142
View File
@@ -567,141 +567,6 @@ bool GLResourceManager::Prepare_InitialState(GLResource res)
return true;
}
void GLResourceManager::CreateTextureImage(GLuint tex, GLenum internalFormat,
GLenum internalFormatHint, GLenum textype, GLint dim,
GLint width, GLint height, GLint depth, GLint samples,
int mips)
{
if(textype == eGL_TEXTURE_BUFFER)
{
return;
}
GLuint ppb = 0, pub = 0;
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb);
GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub);
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0);
if(textype == eGL_TEXTURE_2D_MULTISAMPLE)
{
GL.glTextureStorage2DMultisampleEXT(tex, textype, samples, internalFormat, width, height,
GL_TRUE);
}
else if(textype == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY)
{
GL.glTextureStorage3DMultisampleEXT(tex, textype, samples, internalFormat, width, height, depth,
GL_TRUE);
}
else
{
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAX_LEVEL, mips - 1);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
bool isCompressed = IsCompressedFormat(internalFormat);
GLenum baseFormat = eGL_RGBA;
GLenum dataType = internalFormatHint != eGL_NONE ? internalFormatHint : eGL_UNSIGNED_BYTE;
if(!isCompressed)
{
baseFormat = GetBaseFormat(internalFormat);
if(internalFormatHint == eGL_NONE)
dataType = GetDataType(internalFormat);
}
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(textype != eGL_TEXTURE_CUBE_MAP)
{
targets[0] = textype;
count = 1;
}
GLsizei w = (GLsizei)width;
GLsizei h = (GLsizei)height;
GLsizei d = (GLsizei)depth;
for(int m = 0; m < mips; m++)
{
for(int t = 0; t < count; t++)
{
if(isCompressed)
{
GLsizei compSize = (GLsizei)GetCompressedByteSize(w, h, d, internalFormat);
std::vector<byte> dummy;
dummy.resize(compSize);
if(dim == 1)
GL.glCompressedTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, compSize,
&dummy[0]);
else if(dim == 2)
GL.glCompressedTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, compSize,
&dummy[0]);
else if(dim == 3)
GL.glCompressedTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0,
compSize, &dummy[0]);
}
else
{
if(dim == 1)
GL.glTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, baseFormat, dataType,
NULL);
else if(dim == 2)
GL.glTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, baseFormat,
dataType, NULL);
else if(dim == 3)
GL.glTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, baseFormat,
dataType, NULL);
}
}
w = RDCMAX(1, w >> 1);
if(textype != eGL_TEXTURE_1D_ARRAY)
h = RDCMAX(1, h >> 1);
if(textype != eGL_TEXTURE_2D_ARRAY && textype != eGL_TEXTURE_CUBE_MAP_ARRAY)
d = RDCMAX(1, d >> 1);
}
}
if(IsCaptureMode(m_State))
{
// register this texture and set up its texture details, so it's available for emulation
// readback.
GLResource res = TextureRes(m_Driver->GetCtx(), tex);
ResourceId id = RegisterResource(res);
WrappedOpenGL::TextureData &details = m_Driver->m_Textures[id];
details.resource = res;
details.curType = textype;
details.dimension = dim;
details.emulated = details.view = false;
details.width = width;
details.height = height;
details.depth = depth;
details.samples = samples;
details.creationFlags = TextureCategory::NoFlags;
details.internalFormat = internalFormat;
details.mipsValid = (1 << mips) - 1;
}
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb);
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub);
}
void GLResourceManager::PrepareTextureInitialContents(ResourceId liveid, ResourceId origid,
GLResource res)
{
@@ -840,9 +705,9 @@ void GLResourceManager::PrepareTextureInitialContents(ResourceId liveid, Resourc
mips = 1;
// create texture of identical format/size to store initial contents
CreateTextureImage(tex, details.internalFormat, details.internalFormatHint, details.curType,
details.dimension, details.width, details.height, details.depth,
details.samples, mips);
m_Driver->CreateTextureImage(tex, details.internalFormat, details.internalFormatHint,
details.curType, details.dimension, details.width,
details.height, details.depth, details.samples, mips);
// we need to set maxlevel appropriately for number of mips to force the texture to be
// complete.
@@ -1576,10 +1441,10 @@ bool GLResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceId i
GL.glGenTextures(1, &tex);
GL.glBindTexture(TextureState.type, tex);
CreateTextureImage(tex, TextureState.internalformat, details.internalFormatHint,
TextureState.type, TextureState.dim, TextureState.width,
TextureState.height, TextureState.depth, TextureState.samples,
TextureState.mips);
m_Driver->CreateTextureImage(tex, TextureState.internalformat, details.internalFormatHint,
TextureState.type, TextureState.dim, TextureState.width,
TextureState.height, TextureState.depth,
TextureState.samples, TextureState.mips);
}
else if(ser.IsWriting())
{
-3
View File
@@ -285,9 +285,6 @@ private:
bool Prepare_InitialState(GLResource res);
uint64_t GetSize_InitialState(ResourceId resid, const GLInitialContents &initial);
void CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint,
GLenum textype, GLint dim, GLint width, GLint height, GLint depth,
GLint samples, int mips);
void PrepareTextureInitialContents(ResourceId liveid, ResourceId origid, GLResource res);
void Create_InitialState(ResourceId id, GLResource live, bool hasData);
+194 -9
View File
@@ -113,11 +113,195 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
MakeCurrentReplayContext(m_DebugCtx);
uint32_t numMips = m_CachedTextures[cfg.resourceId].mips;
GLuint castTexture = 0;
GLenum displayFormat = texDetails.internalFormat;
if(cfg.typeCast != CompType::Typeless &&
cfg.typeCast != MakeResourceFormat(target, displayFormat).compType)
{
displayFormat = GetViewCastedFormat(displayFormat, cfg.typeCast);
// if the format didn't change we can't re-interpret this format anyway
if(displayFormat != texDetails.internalFormat)
{
GLMarkerRegion region("Casting texture for view");
drv.glGenTextures(1, &castTexture);
drv.glActiveTexture(eGL_TEXTURE0);
drv.glBindTexture(target, castTexture);
// can't use texture views because the underlying image isn't immutable because we don't
// want to rely on texture storage. We also can't rely on texture views, meaning we need a
// fallback path ANYWAY, so might as well always use it. Yayyy opengl...
drv.CreateTextureImage(castTexture, displayFormat, eGL_NONE, target, texDetails.dimension,
texDetails.width, texDetails.height, texDetails.depth,
texDetails.samples, (int)numMips);
bool isCompressed = IsCompressedFormat(displayFormat);
GLint values[4] = {};
float fvalues[4] = {};
// ensure source texture is complete
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, values);
int prevMaxLevel = values[0];
int maxlevel = numMips - 1;
GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, (GLint *)&maxlevel);
// copy state
if(!texDetails.emulated && (HasExt[ARB_texture_swizzle] || HasExt[EXT_texture_swizzle]))
{
GetTextureSwizzle(texname, target, (GLenum *)values);
SetTextureSwizzle(castTexture, target, (GLenum *)values);
}
if((target == eGL_TEXTURE_CUBE_MAP || target == eGL_TEXTURE_CUBE_MAP_ARRAY) &&
HasExt[ARB_seamless_cubemap_per_texture])
{
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_CUBE_MAP_SEAMLESS, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_CUBE_MAP_SEAMLESS, values);
}
if(target != eGL_TEXTURE_2D_MULTISAMPLE && target != eGL_TEXTURE_2D_MULTISAMPLE_ARRAY)
{
if(HasExt[EXT_texture_sRGB_decode])
{
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_SRGB_DECODE_EXT, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_SRGB_DECODE_EXT, values);
}
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_COMPARE_FUNC, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_COMPARE_FUNC, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_COMPARE_MODE, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_COMPARE_MODE, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MIN_FILTER, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_MIN_FILTER, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MAG_FILTER, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_MAG_FILTER, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_R, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_R, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_S, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_S, values);
GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_T, values);
GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_T, values);
if(HasExt[ARB_texture_border_clamp])
{
GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_BORDER_COLOR, fvalues);
GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_BORDER_COLOR, fvalues);
}
if(!IsGLES)
{
GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_LOD_BIAS, fvalues);
GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_LOD_BIAS, fvalues);
}
if(target != eGL_TEXTURE_RECTANGLE)
{
GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_MIN_LOD, fvalues);
GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_MIN_LOD, fvalues);
GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_MAX_LOD, fvalues);
GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_MAX_LOD, fvalues);
}
}
// copy mip data
for(uint32_t i = 0; i < numMips; i++)
{
int w = RDCMAX(texDetails.width >> i, 1);
int h = RDCMAX(texDetails.height >> i, 1);
int d = RDCMAX(texDetails.depth >> i, 1);
if(target == eGL_TEXTURE_CUBE_MAP)
d *= 6;
else if(target == eGL_TEXTURE_CUBE_MAP_ARRAY || target == eGL_TEXTURE_2D_ARRAY)
d = texDetails.depth;
// glCopyImageSubData treats 1D arrays sanely - with depth as array size - but at odds
// with the rest of the API.
if(target == eGL_TEXTURE_1D_ARRAY)
{
h = 1;
d = texDetails.height;
}
if((isCompressed && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) ||
(isCompressed && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] &&
texDetails.curType == eGL_TEXTURE_CUBE_MAP) ||
(isCompressed && IsGLES))
{
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(target != eGL_TEXTURE_CUBE_MAP)
{
targets[0] = target;
count = 1;
}
for(int trg = 0; trg < count; trg++)
{
size_t size = GetCompressedByteSize(w, h, d, displayFormat);
if(target == eGL_TEXTURE_CUBE_MAP)
size /= 6;
byte *buf = new byte[size];
if(IsGLES)
{
texDetails.GetCompressedImageDataGLES(i, targets[trg], size, buf);
}
else
{
// read to CPU
GL.glGetCompressedTextureImageEXT(texname, targets[trg], i, buf);
}
// write to GPU
if(texDetails.dimension == 1)
GL.glCompressedTextureSubImage1DEXT(castTexture, targets[trg], i, 0, w, displayFormat,
(GLsizei)size, buf);
else if(texDetails.dimension == 2)
GL.glCompressedTextureSubImage2DEXT(castTexture, targets[trg], i, 0, 0, w, h,
displayFormat, (GLsizei)size, buf);
else if(texDetails.dimension == 3)
GL.glCompressedTextureSubImage3DEXT(castTexture, targets[trg], i, 0, 0, 0, w, h, d,
displayFormat, (GLsizei)size, buf);
delete[] buf;
}
}
else
{
GL.glCopyImageSubData(texname, target, i, 0, 0, 0, castTexture, target, i, 0, 0, 0, w, h,
d);
}
}
GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, (GLint *)&prevMaxLevel);
texname = castTexture;
}
}
RDCGLenum dsTexMode = eGL_NONE;
if(IsDepthStencilFormat(texDetails.internalFormat))
if(IsDepthStencilFormat(displayFormat))
{
// stencil-only, make sure we display it as such
if(texDetails.internalFormat == eGL_STENCIL_INDEX8)
if(displayFormat == eGL_STENCIL_INDEX8)
{
cfg.red = false;
cfg.green = true;
@@ -126,7 +310,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
}
// depth-only, make sure we display it as such
if(GetBaseFormat(texDetails.internalFormat) == eGL_DEPTH_COMPONENT)
if(GetBaseFormat(displayFormat) == eGL_DEPTH_COMPONENT)
{
cfg.red = true;
cfg.green = false;
@@ -141,7 +325,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
// Stencil texture sampling is not normalized in OpenGL
intIdx = 1;
float rangeScale = 1.0f;
switch(texDetails.internalFormat)
switch(displayFormat)
{
case eGL_STENCIL_INDEX1: rangeScale = 1.0f; break;
case eGL_STENCIL_INDEX4: rangeScale = 16.0f; break;
@@ -162,17 +346,15 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
}
else
{
if(IsUIntFormat(texDetails.internalFormat))
if(IsUIntFormat(displayFormat))
intIdx = 1;
if(IsSIntFormat(texDetails.internalFormat))
if(IsSIntFormat(displayFormat))
intIdx = 2;
}
drv.glBindProgramPipeline(0);
drv.glUseProgram(DebugData.texDisplayProg[intIdx]);
uint32_t numMips = m_CachedTextures[cfg.resourceId].mips;
GLuint customProgram = 0;
if(cfg.customShaderId != ResourceId() &&
@@ -393,7 +575,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
if(cfg.overlay == DebugOverlay::Clipping)
ubo->OutputDisplayFormat |= TEXDISPLAY_CLIPPING;
if(!IsSRGBFormat(texDetails.internalFormat) && cfg.linearDisplayAsGamma)
if(!IsSRGBFormat(displayFormat) && cfg.linearDisplayAsGamma)
ubo->OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE;
ubo->RawOutput = cfg.rawOutput ? 1 : 0;
@@ -490,5 +672,8 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags)
if(dsTexMode != eGL_NONE && HasExt[ARB_stencil_texturing])
drv.glTexParameteri(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, origDSTexMode);
if(castTexture)
drv.glDeleteTextures(1, &castTexture);
return true;
}
+261
View File
@@ -1048,6 +1048,267 @@ bool IsSRGBFormat(GLenum internalFormat)
return false;
}
GLenum GetViewCastedFormat(GLenum internalFormat, CompType typeCast)
{
switch(internalFormat)
{
case eGL_RGBA:
case eGL_RGBA8:
case eGL_RGBA8_SNORM:
case eGL_RGBA8UI:
case eGL_RGBA8I:
case eGL_SRGB_ALPHA:
case eGL_SRGB8_ALPHA8:
switch(typeCast)
{
case CompType::UNorm: internalFormat = eGL_RGBA8; break;
case CompType::SNorm: internalFormat = eGL_RGBA8_SNORM; break;
case CompType::UInt: internalFormat = eGL_RGBA8UI; break;
case CompType::SInt: internalFormat = eGL_RGBA8I; break;
case CompType::UNormSRGB: internalFormat = eGL_SRGB8_ALPHA8; break;
default: break;
}
break;
case eGL_RGB:
case eGL_RGB8:
case eGL_RGB8_SNORM:
case eGL_RGB8UI:
case eGL_RGB8I:
case eGL_SRGB:
case eGL_SRGB8:
switch(typeCast)
{
case CompType::UNorm: internalFormat = eGL_RGB8; break;
case CompType::SNorm: internalFormat = eGL_RGB8_SNORM; break;
case CompType::UInt: internalFormat = eGL_RGB8UI; break;
case CompType::SInt: internalFormat = eGL_RGB8I; break;
case CompType::UNormSRGB: internalFormat = eGL_SRGB8; break;
default: break;
}
break;
case eGL_RG:
case eGL_RG8:
case eGL_RG8_SNORM:
case eGL_RG8UI:
case eGL_RG8I:
switch(typeCast)
{
case CompType::UNorm: internalFormat = eGL_RG8; break;
case CompType::SNorm: internalFormat = eGL_RG8_SNORM; break;
case CompType::UInt: internalFormat = eGL_RG8UI; break;
case CompType::SInt: internalFormat = eGL_RG8I; break;
case CompType::UNormSRGB: internalFormat = eGL_SRG8_EXT; break;
default: break;
}
break;
case eGL_RED:
case eGL_R8:
case eGL_R8_SNORM:
case eGL_R8UI:
case eGL_R8I:
switch(typeCast)
{
case CompType::UNorm: internalFormat = eGL_R8; break;
case CompType::SNorm: internalFormat = eGL_R8_SNORM; break;
case CompType::UInt: internalFormat = eGL_R8UI; break;
case CompType::SInt: internalFormat = eGL_R8I; break;
case CompType::UNormSRGB: internalFormat = eGL_SR8_EXT; break;
default: break;
}
break;
case eGL_RGBA16F:
case eGL_RGBA16:
case eGL_RGBA16_SNORM:
case eGL_RGBA16UI:
case eGL_RGBA16I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RGBA16F; break;
case CompType::UNorm: internalFormat = eGL_RGBA16; break;
case CompType::SNorm: internalFormat = eGL_RGBA16_SNORM; break;
case CompType::UInt: internalFormat = eGL_RGBA16UI; break;
case CompType::SInt: internalFormat = eGL_RGBA16I; break;
default: break;
}
break;
case eGL_RGB16F:
case eGL_RGB16:
case eGL_RGB16_SNORM:
case eGL_RGB16UI:
case eGL_RGB16I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RGB16F; break;
case CompType::UNorm: internalFormat = eGL_RGB16; break;
case CompType::SNorm: internalFormat = eGL_RGB16_SNORM; break;
case CompType::UInt: internalFormat = eGL_RGB16UI; break;
case CompType::SInt: internalFormat = eGL_RGB16I; break;
default: break;
}
break;
case eGL_RG16F:
case eGL_RG16:
case eGL_RG16_SNORM:
case eGL_RG16UI:
case eGL_RG16I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RG16F; break;
case CompType::UNorm: internalFormat = eGL_RG16; break;
case CompType::SNorm: internalFormat = eGL_RG16_SNORM; break;
case CompType::UInt: internalFormat = eGL_RG16UI; break;
case CompType::SInt: internalFormat = eGL_RG16I; break;
default: break;
}
break;
case eGL_R16F:
case eGL_R16:
case eGL_R16_SNORM:
case eGL_R16UI:
case eGL_R16I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_R16F; break;
case CompType::UNorm: internalFormat = eGL_R16; break;
case CompType::SNorm: internalFormat = eGL_R16_SNORM; break;
case CompType::UInt: internalFormat = eGL_R16UI; break;
case CompType::SInt: internalFormat = eGL_R16I; break;
default: break;
}
break;
case eGL_RGBA32F:
case eGL_RGBA32UI:
case eGL_RGBA32I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RGBA32F; break;
case CompType::UInt: internalFormat = eGL_RGBA32UI; break;
case CompType::SInt: internalFormat = eGL_RGBA32I; break;
default: break;
}
break;
case eGL_RGB32F:
case eGL_RGB32UI:
case eGL_RGB32I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RGB32F; break;
case CompType::UInt: internalFormat = eGL_RGB32UI; break;
case CompType::SInt: internalFormat = eGL_RGB32I; break;
default: break;
}
break;
case eGL_RG32F:
case eGL_RG32UI:
case eGL_RG32I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_RG32F; break;
case CompType::UInt: internalFormat = eGL_RG32UI; break;
case CompType::SInt: internalFormat = eGL_RG32I; break;
default: break;
}
break;
case eGL_R32F:
case eGL_R32UI:
case eGL_R32I:
switch(typeCast)
{
case CompType::Float: internalFormat = eGL_R32F; break;
case CompType::UInt: internalFormat = eGL_R32UI; break;
case CompType::SInt: internalFormat = eGL_R32I; break;
default: break;
}
break;
case eGL_RGB10_A2UI:
case eGL_RGB10_A2:
switch(typeCast)
{
case CompType::Float:
case CompType::UNorm: internalFormat = eGL_RGB10_A2; break;
case CompType::UInt: internalFormat = eGL_RGB10_A2UI; break;
default: break;
}
break;
case eGL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT
: eGL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case eGL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
: eGL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
break;
case eGL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
: eGL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
: eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
case eGL_COMPRESSED_RED_RGTC1:
case eGL_COMPRESSED_SIGNED_RED_RGTC1:
internalFormat = (typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RED_RGTC1
: eGL_COMPRESSED_RED_RGTC1;
break;
case eGL_COMPRESSED_RG_RGTC2:
case eGL_COMPRESSED_SIGNED_RG_RGTC2:
internalFormat =
(typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RG_RGTC2 : eGL_COMPRESSED_RG_RGTC2;
break;
case eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
case eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
internalFormat = (typeCast == CompType::SNorm) ? eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB
: eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
break;
case eGL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
case eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB
: eGL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
break;
case eGL_COMPRESSED_SIGNED_R11_EAC:
case eGL_COMPRESSED_R11_EAC:
internalFormat =
(typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_R11_EAC : eGL_COMPRESSED_R11_EAC;
break;
case eGL_COMPRESSED_SIGNED_RG11_EAC:
case eGL_COMPRESSED_RG11_EAC:
internalFormat =
(typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RG11_EAC : eGL_COMPRESSED_RG11_EAC;
break;
default: break;
}
return internalFormat;
}
GLenum TextureBinding(GLenum target)
{
switch(target)
+2
View File
@@ -52,6 +52,8 @@ bool IsUIntFormat(GLenum internalFormat);
bool IsSIntFormat(GLenum internalFormat);
bool IsSRGBFormat(GLenum internalFormat);
GLenum GetViewCastedFormat(GLenum internalFormat, CompType typeCast);
bool IsCubeFace(GLenum target);
GLint CubeTargetIndex(GLenum face);
GLenum TextureBinding(GLenum target);