Implement GetTextureData for GL - underlying code behind texture saving

* This should support all forms of textures off the bat, multisampled
  textures, 3D textures, arrays, compressed and uncompressed, etc.
This commit is contained in:
baldurk
2015-02-09 17:29:13 +00:00
parent bdb823c20b
commit 8ccf071865
16 changed files with 502 additions and 22 deletions
+1
View File
@@ -75,6 +75,7 @@ data/glsl/mesh.geomo \
data/glsl/text.verto \
data/glsl/text.frago \
data/glsl/histogram.compo \
data/glsl/arraymscopy.compo \
data/sourcecodepro.ttfo
.PHONY: all
+2
View File
@@ -166,6 +166,8 @@ enum SpecialFormat
eSpecial_BC5,
eSpecial_BC6,
eSpecial_BC7,
eSpecial_ETC2,
eSpecial_EAC,
eSpecial_R10G10B10A2,
eSpecial_R11G11B10,
eSpecial_B5G6R5,
+14 -2
View File
@@ -509,6 +509,8 @@ DXGI_FORMAT ResourceFormat2DXGIFormat(ResourceFormat format)
case eSpecial_D32S8:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
default:
case eSpecial_ETC2:
case eSpecial_EAC:
case eSpecial_YUV:
RDCERR("Unsupported writing format %u", format.specialFormat);
return DXGI_FORMAT_UNKNOWN;
@@ -680,6 +682,11 @@ bool write_dds_to_file(FILE *f, const dds_data &data)
case eSpecial_BC6:
case eSpecial_BC7:
blockFormat = true;
break;
case eSpecial_ETC2:
case eSpecial_EAC:
RDCERR("Unsupported file format, ETC2/EAC");
return false;
default:
break;
}
@@ -745,7 +752,7 @@ bool write_dds_to_file(FILE *f, const dds_data &data)
bytesPerPixel = 5;
break;
case eSpecial_YUV:
RDCERR("Unsupported file save format");
RDCERR("Unsupported file format");
return false;
default:
bytesPerPixel = data.format.compCount*data.format.compByteWidth;
@@ -1014,7 +1021,7 @@ dds_data load_dds_from_file(FILE *f)
bytesPerPixel = 5;
break;
case eSpecial_YUV:
RDCERR("Unsupported file save format");
RDCERR("Unsupported file format, YUV");
return error;
default:
bytesPerPixel = ret.format.compCount*ret.format.compByteWidth;
@@ -1034,6 +1041,11 @@ dds_data load_dds_from_file(FILE *f)
case eSpecial_BC6:
case eSpecial_BC7:
blockFormat = true;
break;
case eSpecial_ETC2:
case eSpecial_EAC:
RDCERR("Unsupported file format, ETC2/EAC");
return error;
default:
break;
}
+1
View File
@@ -35,6 +35,7 @@ DECLARE_EMBED(blit_frag);
DECLARE_EMBED(texdisplay_frag);
DECLARE_EMBED(checkerboard_frag);
DECLARE_EMBED(histogram_comp);
DECLARE_EMBED(arraymscopy_comp);
DECLARE_EMBED(mesh_vert);
DECLARE_EMBED(mesh_frag);
DECLARE_EMBED(mesh_geom);
+65
View File
@@ -0,0 +1,65 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#extension GL_ARB_compute_shader : require
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform int numMultiSamples;
layout(binding = 0) uniform usampler2DMSArray srcMS;
layout(binding = 0) writeonly uniform uimage2DArray dstArray;
void MS2Array()
{
uvec3 id = gl_GlobalInvocationID;
int slice = int(id.z / numMultiSamples);
int sampleIdx = int(id.z % numMultiSamples);
uvec4 data = texelFetch(srcMS, ivec3(int(id.x), int(id.y), slice), sampleIdx);
imageStore(dstArray, ivec3(int(id.x), int(id.y), int(id.z)), data);
}
layout(binding = 0) uniform usampler2DArray srcArray;
layout(binding = 0) writeonly uniform uimage2DMSArray dstMS;
void Array2MS()
{
uvec3 id = gl_GlobalInvocationID;
int slice = int(id.z / numMultiSamples);
int sampleIdx = int(id.z % numMultiSamples);
uvec4 data = texelFetch(srcArray, ivec3(int(id.x), int(id.y), int(id.z)), 0);
imageStore(dstMS, ivec3(int(id.x), int(id.y), slice), sampleIdx, data);
}
+1
View File
@@ -123,6 +123,7 @@ RESOURCE_texsample_h TYPE_EMBED "glsl/texsample.h"
RESOURCE_histogram_comp TYPE_EMBED "glsl/histogram.comp"
RESOURCE_mesh_frag TYPE_EMBED "glsl/mesh.frag"
RESOURCE_mesh_geom TYPE_EMBED "glsl/mesh.geom"
RESOURCE_arraymscopy_comp TYPE_EMBED "glsl/arraymscopy.comp"
RESOURCE_sourcecodepro_ttf TYPE_EMBED "sourcecodepro.ttf"
+1
View File
@@ -25,6 +25,7 @@
#define RESOURCE_histogram_comp 212
#define RESOURCE_mesh_frag 213
#define RESOURCE_mesh_geom 214
#define RESOURCE_arraymscopy_comp 215
#define RESOURCE_sourcecodepro_ttf 301
+71 -2
View File
@@ -344,6 +344,18 @@ void GLReplay::InitDebugData()
gl.glNamedBufferStorageEXT(DebugData.minmaxResult, sizeof(Vec4f)*2, NULL, GL_MAP_READ_BIT);
gl.glNamedBufferStorageEXT(DebugData.histogramBuf, sizeof(uint32_t)*HGRAM_NUM_BUCKETS, NULL, GL_MAP_READ_BIT);
}
{
string glsl = "#version 420 core\n\n#define MS2Array main\n\n";
glsl += GetEmbeddedResource(arraymscopy_comp);
DebugData.MS2Array = CreateCShaderProgram(glsl.c_str());
glsl = "#version 420 core\n\n#define Array2MS main\n\n";
glsl += GetEmbeddedResource(arraymscopy_comp);
DebugData.Array2MS = CreateCShaderProgram(glsl.c_str());
}
gl.glGenVertexArrays(1, &DebugData.meshVAO);
gl.glBindVertexArray(DebugData.meshVAO);
@@ -479,6 +491,9 @@ void GLReplay::DeleteDebugData()
gl.glDeleteProgram(DebugData.minmaxResultProgram[i]);
}
}
gl.glDeleteProgram(DebugData.Array2MS);
gl.glDeleteProgram(DebugData.MS2Array);
gl.glDeleteBuffers(1, &DebugData.minmaxTileResult);
gl.glDeleteBuffers(1, &DebugData.minmaxResult);
@@ -853,13 +868,67 @@ void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sl
texDisplay.offx = -float(x);
texDisplay.offy = -float(y);
RenderTexture(texDisplay);
RenderTextureInternal(texDisplay, false);
}
gl.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixel);
}
void GLReplay::CopyTex2DMSToArray(GLuint destArray, GLuint srcMS, GLint width, GLint height, GLint arraySize, GLint samples, GLenum intFormat)
{
WrappedOpenGL &gl = *m_pDriver;
GLRenderState rs(&gl.GetHookset(), NULL, READING);
rs.FetchState(m_pDriver->GetCtx(), m_pDriver);
GLenum viewClass;
gl.glGetInternalformativ(eGL_TEXTURE_2D_ARRAY, intFormat, eGL_VIEW_COMPATIBILITY_CLASS, sizeof(GLenum), (GLint *)&viewClass);
GLenum fmt = eGL_R32UI;
if(viewClass == eGL_VIEW_CLASS_8_BITS) fmt = eGL_R8UI;
else if(viewClass == eGL_VIEW_CLASS_16_BITS) fmt = eGL_R16UI;
else if(viewClass == eGL_VIEW_CLASS_24_BITS) fmt = eGL_RGB8UI;
else if(viewClass == eGL_VIEW_CLASS_32_BITS) fmt = eGL_RGBA8UI;
else if(viewClass == eGL_VIEW_CLASS_48_BITS) fmt = eGL_RGB16UI;
else if(viewClass == eGL_VIEW_CLASS_64_BITS) fmt = eGL_RG32UI;
else if(viewClass == eGL_VIEW_CLASS_96_BITS) fmt = eGL_RGB32UI;
else if(viewClass == eGL_VIEW_CLASS_128_BITS) fmt = eGL_RGBA32UI;
GLuint texs[2];
gl.glGenTextures(2, texs);
gl.glTextureView(texs[0], eGL_TEXTURE_2D_ARRAY, destArray, fmt, 0, 1, 0, arraySize*samples);
gl.glTextureView(texs[1], eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, srcMS, fmt, 0, 1, 0, arraySize);
gl.glBindImageTexture(0, texs[0], 0, GL_TRUE, 0, eGL_WRITE_ONLY, fmt);
gl.glActiveTexture(eGL_TEXTURE0);
gl.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[1]);
gl.glBindSampler(0, DebugData.pointNoMipSampler);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0);
gl.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAX_LEVEL, 1);
gl.glUseProgram(DebugData.MS2Array);
GLint loc = gl.glGetUniformLocation(DebugData.MS2Array, "numMultiSamples");
gl.glUniform1i(loc, samples);
gl.glDispatchCompute((GLuint)width, (GLuint)height, GLuint(arraySize*samples));
gl.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
gl.glDeleteTextures(2, texs);
rs.ApplyState(m_pDriver->GetCtx(), m_pDriver);
}
bool GLReplay::RenderTexture(TextureDisplay cfg)
{
return RenderTextureInternal(cfg, true);
}
bool GLReplay::RenderTextureInternal(TextureDisplay cfg, bool blendAlpha)
{
WrappedOpenGL &gl = *m_pDriver;
@@ -1119,7 +1188,7 @@ bool GLReplay::RenderTexture(TextureDisplay cfg)
gl.glUnmapBuffer(eGL_UNIFORM_BUFFER);
if(cfg.rawoutput)
if(cfg.rawoutput || !blendAlpha)
{
gl.glDisable(eGL_BLEND);
}
+21 -12
View File
@@ -44,6 +44,25 @@ void PixelUnpackState::Fetch(const GLHookSet *funcs, bool compressed)
}
}
void PixelUnpackState::Apply(const GLHookSet *funcs, bool compressed)
{
funcs->glPixelStorei(eGL_UNPACK_SWAP_BYTES, swapBytes);
funcs->glPixelStorei(eGL_UNPACK_ROW_LENGTH, rowlength);
funcs->glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, imageheight);
funcs->glPixelStorei(eGL_UNPACK_SKIP_PIXELS, skipPixels);
funcs->glPixelStorei(eGL_UNPACK_SKIP_ROWS, skipRows);
funcs->glPixelStorei(eGL_UNPACK_SKIP_IMAGES, skipImages);
funcs->glPixelStorei(eGL_UNPACK_ALIGNMENT, alignment);
if(compressed)
{
funcs->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_WIDTH, compressedBlockWidth);
funcs->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_HEIGHT, compressedBlockHeight);
funcs->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_DEPTH, compressedBlockDepth);
funcs->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_SIZE, compressedBlockSize);
}
}
bool PixelUnpackState::FastPath(GLsizei width, GLsizei height, GLsizei depth, GLenum dataformat, GLenum basetype)
{
if(swapBytes)
@@ -845,18 +864,8 @@ void GLRenderState::ApplyState(void *ctx, WrappedOpenGL *gl)
m_Real->glFrontFace(FrontFace);
m_Real->glCullFace(CullFace);
m_Real->glPixelStorei(eGL_UNPACK_SWAP_BYTES, Unpack.swapBytes);
m_Real->glPixelStorei(eGL_UNPACK_ROW_LENGTH, Unpack.rowlength);
m_Real->glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, Unpack.imageheight);
m_Real->glPixelStorei(eGL_UNPACK_SKIP_PIXELS, Unpack.skipPixels);
m_Real->glPixelStorei(eGL_UNPACK_SKIP_ROWS, Unpack.skipRows);
m_Real->glPixelStorei(eGL_UNPACK_SKIP_IMAGES, Unpack.skipImages);
m_Real->glPixelStorei(eGL_UNPACK_ALIGNMENT, Unpack.alignment);
m_Real->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_WIDTH, Unpack.compressedBlockWidth);
m_Real->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_HEIGHT, Unpack.compressedBlockHeight);
m_Real->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_DEPTH, Unpack.compressedBlockDepth);
m_Real->glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_SIZE, Unpack.compressedBlockSize);
Unpack.Apply(m_Real, true);
}
void GLRenderState::Clear()
+1
View File
@@ -42,6 +42,7 @@ struct PixelUnpackState
int32_t compressedBlockSize;
void Fetch(const GLHookSet *funcs, bool compressed);
void Apply(const GLHookSet *funcs, bool compressed);
bool FastPath(GLsizei width, GLsizei height, GLsizei depth, GLenum dataformat=eGL_NONE, GLenum basetype=eGL_NONE);
byte *Unpack(byte *pixels, GLsizei width, GLsizei height, GLsizei depth, GLenum dataformat, GLenum basetype);
+307 -6
View File
@@ -2168,6 +2168,313 @@ void GLReplay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector
FillCBufferVariables(gl, curProg, cblock.bufferBacked ? true : false, "", cblock.variables, outvars, data);
}
byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize)
{
WrappedOpenGL &gl = *m_pDriver;
auto &texDetails = m_pDriver->m_Textures[tex];
byte *ret = NULL;
GLuint tempTex = 0;
GLenum texType = texDetails.curType;
GLuint texname = texDetails.resource.name;
GLenum intFormat = texDetails.internalFormat;
GLsizei width = RDCMAX(1, texDetails.width>>mip);
GLsizei height = RDCMAX(1, texDetails.height>>mip);
GLsizei depth = RDCMAX(1, texDetails.depth>>mip);
GLsizei arraysize = 1;
GLint samples = texDetails.samples;
if(texType == eGL_TEXTURE_2D_ARRAY ||
texType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY ||
texType == eGL_TEXTURE_1D_ARRAY ||
texType == eGL_TEXTURE_CUBE_MAP ||
texType == eGL_TEXTURE_CUBE_MAP_ARRAY)
{
// array size doesn't get mip'd down
depth = texDetails.depth;
arraysize = texDetails.depth;
}
if(forceRGBA8unorm && intFormat != eGL_RGBA8 && intFormat != eGL_SRGB8_ALPHA8)
{
MakeCurrentReplayContext(m_DebugCtx);
GLenum finalFormat = IsSRGBFormat(intFormat) ? eGL_SRGB8_ALPHA8 : eGL_RGBA8;
GLenum newtarget = (texType == eGL_TEXTURE_3D ? eGL_TEXTURE_3D : eGL_TEXTURE_2D);
// create temporary texture of width/height in RGBA8 format to render to
gl.glGenTextures(1, &tempTex);
gl.glBindTexture(newtarget, tempTex);
if(newtarget == eGL_TEXTURE_3D)
gl.glTexStorage3D(newtarget, 1, finalFormat, width, height, depth);
else
gl.glTexStorage2D(newtarget, 1, finalFormat, width, height);
// create temp framebuffer
GLuint fbo = 0;
gl.glGenFramebuffers(1, &fbo);
gl.glBindFramebuffer(eGL_FRAMEBUFFER, fbo);
gl.glTexParameteri(newtarget, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
gl.glTexParameteri(newtarget, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
gl.glTexParameteri(newtarget, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
gl.glTexParameteri(newtarget, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE);
gl.glTexParameteri(newtarget, eGL_TEXTURE_WRAP_R, eGL_CLAMP_TO_EDGE);
if(newtarget == eGL_TEXTURE_3D)
gl.glFramebufferTexture3D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, eGL_TEXTURE_3D, tempTex, 0, 0);
else
gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, tempTex, 0);
float col[] = { 0.3f, 0.6f, 0.9f, 1.0f };
gl.glClearBufferfv(eGL_COLOR, 0, col);
// render to the temp texture to do the downcast
float w = DebugData.outWidth;
float h = DebugData.outHeight;
DebugData.outWidth = float(width); DebugData.outHeight = float(height);
for(GLsizei d=0; d < (newtarget == eGL_TEXTURE_3D ? depth : 1); d++)
{
TextureDisplay texDisplay;
texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true;
texDisplay.HDRMul = -1.0f;
texDisplay.linearDisplayAsGamma = false;
texDisplay.overlay = eTexOverlay_None;
texDisplay.FlipY = false;
texDisplay.mip = mip;
texDisplay.sampleIdx = ~0U;
texDisplay.CustomShader = ResourceId();
texDisplay.sliceFace = arrayIdx;
texDisplay.rangemin = blackPoint;
texDisplay.rangemax = whitePoint;
texDisplay.scale = 1.0f;
texDisplay.texid = tex;
texDisplay.rawoutput = false;
texDisplay.offx = 0;
texDisplay.offy = 0;
if(newtarget == eGL_TEXTURE_3D)
{
gl.glFramebufferTexture3D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, eGL_TEXTURE_3D, tempTex, 0, (GLint)d);
texDisplay.sliceFace = (uint32_t)d;
}
gl.glViewport(0, 0, width, height);
RenderTextureInternal(texDisplay, false);
}
// rewrite the variables to temporary texture
texType = newtarget;
texname = tempTex;
intFormat = finalFormat;
if(newtarget == eGL_TEXTURE_2D) depth = 1;
arraysize = 1;
samples = 1;
gl.glDeleteFramebuffers(1, &fbo);
}
else if(resolve && samples > 1)
{
MakeCurrentReplayContext(m_DebugCtx);
GLuint curDrawFBO = 0;
GLuint curReadFBO = 0;
gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curDrawFBO);
gl.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint*)&curReadFBO);
// create temporary texture of width/height in same format to render to
gl.glGenTextures(1, &tempTex);
gl.glBindTexture(eGL_TEXTURE_2D, tempTex);
gl.glTexStorage2D(eGL_TEXTURE_2D, 1, intFormat, width, height);
// create temp framebuffers
GLuint fbos[2] = { 0 };
gl.glGenFramebuffers(2, fbos);
gl.glBindFramebuffer(eGL_FRAMEBUFFER, fbos[0]);
gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, tempTex, 0);
gl.glBindFramebuffer(eGL_FRAMEBUFFER, fbos[1]);
if(texType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY)
gl.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texname, 0, arrayIdx);
else
gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texname, 0);
// do default resolve (framebuffer blit)
gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, fbos[0]);
gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, fbos[1]);
float col[] = { 0.3f, 0.4f, 0.5f, 1.0f };
gl.glClearBufferfv(eGL_COLOR, 0, col);
gl.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, eGL_NEAREST);
// rewrite the variables to temporary texture
texType = eGL_TEXTURE_2D;
texname = tempTex;
depth = 1;
arraysize = 1;
samples = 1;
gl.glDeleteFramebuffers(2, fbos);
gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, curDrawFBO);
gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curReadFBO);
}
else if(samples > 1)
{
MakeCurrentReplayContext(m_DebugCtx);
// create temporary texture array of width/height in same format to render to,
// with the same number of array slices as multi samples.
gl.glGenTextures(1, &tempTex);
gl.glBindTexture(eGL_TEXTURE_2D_ARRAY, tempTex);
gl.glTexStorage3D(eGL_TEXTURE_2D_ARRAY, 1, intFormat, width, height, arraysize*samples);
// copy multisampled texture to an array
CopyTex2DMSToArray(tempTex, texname, width, height, arraysize, samples, intFormat);
// rewrite the variables to temporary texture
texType = eGL_TEXTURE_2D_ARRAY;
texname = tempTex;
depth = 1;
depth = samples;
arraysize = samples;
samples = 1;
}
// fetch and return data now
{
PixelUnpackState unpack;
unpack.Fetch(&gl.GetHookset(), true);
PixelUnpackState identity = {0};
identity.alignment = 1;
identity.Apply(&gl.GetHookset(), true);
GLenum binding = TextureBinding(texType);
GLuint prevtex = 0;
gl.glGetIntegerv(binding, (GLint *)&prevtex);
gl.glBindTexture(texType, texname);
GLenum target = texType;
if(texType == 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,
};
RDCASSERT(arrayIdx < ARRAY_COUNT(targets));
target = targets[arrayIdx];
}
if(IsCompressedFormat(intFormat))
{
GLuint compSize;
gl.glGetTexLevelParameteriv(target, mip, eGL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&compSize);
dataSize = compSize;
ret = new byte[dataSize];
gl.glGetCompressedTexImage(target, mip, ret);
}
else
{
GLenum fmt = GetBaseFormat(intFormat);
GLenum type = GetDataType(intFormat);
dataSize = GetByteSize(width, height, depth, fmt, type);
ret = new byte[dataSize];
m_pDriver->glGetTexImage(target, (GLint)mip, fmt, type, ret);
// need to vertically flip the image now to get conventional row ordering
// we either do this when copying out the slice of interest, or just
// on its own
size_t rowSize = GetByteSize(width, 1, 1, fmt, type);
byte *src, *dst;
// for arrays just extract the slice we're interested in.
if(texType == eGL_TEXTURE_2D_ARRAY ||
texType == eGL_TEXTURE_1D_ARRAY ||
texType == eGL_TEXTURE_CUBE_MAP_ARRAY)
{
dataSize = GetByteSize(width, height, 1, fmt, type);
byte *slice = new byte[dataSize];
// src points to the last row in the array slice image
src = (ret + dataSize*arrayIdx) + (height-1)*rowSize;
dst = slice;
// we do memcpy + vertical flip
//memcpy(slice, ret + dataSize*arrayIdx, dataSize);
for(GLsizei i=0; i < height; i++)
{
memcpy(dst, src, rowSize);
dst += rowSize;
src -= rowSize;
}
delete[] ret;
ret = slice;
}
else
{
byte *row = new byte[rowSize];
size_t sliceSize = GetByteSize(width, height, 1, fmt, type);
// invert all slices in a 3D texture
for(GLsizei d=0; d < depth; d++)
{
dst = ret + d*sliceSize;
src = dst + (height-1)*rowSize;
for(GLsizei i=0; i < height>>1; i++)
{
memcpy(row, src, rowSize);
memcpy(src, dst, rowSize);
memcpy(dst, row, rowSize);
dst += rowSize;
src -= rowSize;
}
}
delete[] row;
}
}
unpack.Apply(&gl.GetHookset(), true);
gl.glBindTexture(texType, prevtex);
}
if(tempTex)
gl.glDeleteTextures(1, &tempTex);
return ret;
}
#pragma endregion
vector<EventUsage> GLReplay::GetUsage(ResourceId id)
@@ -2191,12 +2498,6 @@ void GLReplay::FreeCustomShader(ResourceId id)
RDCUNIMPLEMENTED("FreeCustomShader");
}
byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize)
{
RDCUNIMPLEMENTED("GetTextureData");
return NULL;
}
void GLReplay::ReplaceResource(ResourceId from, ResourceId to)
{
RDCUNIMPLEMENTED("ReplaceResource");
+6
View File
@@ -152,6 +152,7 @@ class GLReplay : public IReplayDriver
void FreeCustomShader(ResourceId id);
bool RenderTexture(TextureDisplay cfg);
bool RenderTextureInternal(TextureDisplay cfg, bool blendAlpha);
void RenderCheckerboard(Vec3f light, Vec3f dark);
@@ -194,6 +195,9 @@ class GLReplay : public IReplayDriver
const vector<byte> &data);
void GetMapping(WrappedOpenGL &gl, GLuint curProg, int shadIdx, ShaderReflection *refl, ShaderBindpointMapping &mapping);
void CopyArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, GLint height, GLint arraySize, GLint samples, GLenum intFormat);
void CopyTex2DMSToArray(GLuint destArray, GLuint srcMS, GLint width, GLint height, GLint arraySize, GLint samples, GLenum intFormat);
struct OutputWindow : public GLWindowingData
{
@@ -250,6 +254,8 @@ class GLReplay : public IReplayDriver
GLuint texDisplayProg[3]; // float/uint/sint
GLuint MS2Array, Array2MS;
GLuint pointSampler;
GLuint pointNoMipSampler;
GLuint linearSampler;
+1
View File
@@ -366,6 +366,7 @@
<ResourceCompile Include="data\renderdoc.rc" />
</ItemGroup>
<ItemGroup>
<None Include="data\glsl\arraymscopy.comp" />
<None Include="data\glsl\blit.frag" />
<None Include="data\glsl\blit.vert" />
<None Include="data\glsl\checkerboard.frag" />
+3
View File
@@ -607,6 +607,9 @@
<None Include="data\glsl\mesh.geom">
<Filter>Resources\glsl</Filter>
</None>
<None Include="data\glsl\arraymscopy.comp">
<Filter>Resources\glsl</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="data\renderdoc.rc">
+5
View File
@@ -601,6 +601,11 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path)
// force downcast to be able to do grid mappings
if(sd.slice.cubeCruciform || sd.slice.slicesAsGrid)
downcast = true;
// we don't support any file formats that handle these block compression formats
if(td.format.specialFormat == eSpecial_ETC2 ||
td.format.specialFormat == eSpecial_EAC)
downcast = true;
// for DDS don't downcast, for non-HDR always downcast if we're not already RGBA8 unorm
// for HDR&EXR we can convert from most regular types as well as 10.10.10.2 and 11.11.10
+2
View File
@@ -168,6 +168,8 @@ namespace renderdoc
BC5,
BC6,
BC7,
ETC2,
EAC,
R10G10B10A2,
R11G11B10,
B5G6R5,