mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 13:00:32 +00:00
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:
@@ -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
|
||||
|
||||
@@ -166,6 +166,8 @@ enum SpecialFormat
|
||||
eSpecial_BC5,
|
||||
eSpecial_BC6,
|
||||
eSpecial_BC7,
|
||||
eSpecial_ETC2,
|
||||
eSpecial_EAC,
|
||||
eSpecial_R10G10B10A2,
|
||||
eSpecial_R11G11B10,
|
||||
eSpecial_B5G6R5,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -168,6 +168,8 @@ namespace renderdoc
|
||||
BC5,
|
||||
BC6,
|
||||
BC7,
|
||||
ETC2,
|
||||
EAC,
|
||||
R10G10B10A2,
|
||||
R11G11B10,
|
||||
B5G6R5,
|
||||
|
||||
Reference in New Issue
Block a user