implemented texture_get_data() for TextureLayered
This commit is contained in:
parent
4f4e46edd5
commit
dddfe9a2df
2 changed files with 144 additions and 4 deletions
|
@ -1056,6 +1056,128 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
|
|||
return texture->images[p_layer];
|
||||
}
|
||||
|
||||
// 3D textures and 2D texture arrays need special treatment, as the glGetTexImage reads **the whole**
|
||||
// texture to host-memory. 3D textures and 2D texture arrays are potentially very big, so reading
|
||||
// everything just to throw everything but one layer away is A Bad Idea.
|
||||
//
|
||||
// Unfortunately, to solve this, the copy shader has to read the data out via a shader and store it
|
||||
// in a temporary framebuffer. The data from the framebuffer can then be read using glReadPixels.
|
||||
if (texture->type == VS::TEXTURE_TYPE_2D_ARRAY || texture->type == VS::TEXTURE_TYPE_3D) {
|
||||
// can't read a layer that doesn't exist
|
||||
ERR_FAIL_INDEX_V(p_layer, texture->alloc_depth, Ref<Image>());
|
||||
|
||||
// get some information about the texture
|
||||
Image::Format real_format;
|
||||
GLenum gl_format;
|
||||
GLenum gl_internal_format;
|
||||
GLenum gl_type;
|
||||
|
||||
bool compressed;
|
||||
bool srgb;
|
||||
|
||||
_get_gl_image_and_format(
|
||||
Ref<Image>(),
|
||||
texture->format,
|
||||
texture->flags,
|
||||
real_format,
|
||||
gl_format,
|
||||
gl_internal_format,
|
||||
gl_type,
|
||||
compressed,
|
||||
srgb);
|
||||
|
||||
PoolVector<uint8_t> data;
|
||||
|
||||
// TODO need to decide between RgbaUnorm and RgbaFloat32 for output
|
||||
int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
|
||||
|
||||
data.resize(data_size * 2); // add some more memory at the end, just in case for buggy drivers
|
||||
PoolVector<uint8_t>::Write wb = data.write();
|
||||
|
||||
// generate temporary resources
|
||||
GLuint tmp_fbo;
|
||||
glGenFramebuffers(1, &tmp_fbo);
|
||||
|
||||
GLuint tmp_color_attachment;
|
||||
glGenTextures(1, &tmp_color_attachment);
|
||||
|
||||
// now bring the OpenGL context into the correct state
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fbo);
|
||||
|
||||
// back color attachment with memory, then set properties
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tmp_color_attachment);
|
||||
// TODO support HDR properly
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// use the color texture as color attachment for this render pass
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_color_attachment, 0);
|
||||
|
||||
// more GL state, wheeeey
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glColorMask(1, 1, 1, 1);
|
||||
|
||||
// use volume tex for reading
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(texture->target, texture->tex_id);
|
||||
|
||||
glViewport(0, 0, texture->alloc_width, texture->alloc_height);
|
||||
|
||||
// set up copy shader for proper use
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb);
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, texture->type == VS::TEXTURE_TYPE_3D);
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, texture->type == VS::TEXTURE_TYPE_2D_ARRAY);
|
||||
shaders.copy.bind();
|
||||
|
||||
// calculate the normalized z coordinate for the layer
|
||||
float layer = (float)p_layer / (float)texture->alloc_depth;
|
||||
|
||||
shaders.copy.set_uniform(CopyShaderGLES3::LAYER, layer);
|
||||
|
||||
glBindVertexArray(resources.quadie_array);
|
||||
}
|
||||
|
||||
// clear color attachment, then perform copy
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
// read the image into the host buffer
|
||||
glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]);
|
||||
|
||||
// remove temp resources and unset some GL state
|
||||
{
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, false);
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, false);
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glDeleteTextures(1, &tmp_color_attachment);
|
||||
glDeleteFramebuffers(1, &tmp_fbo);
|
||||
}
|
||||
|
||||
wb = PoolVector<uint8_t>::Write();
|
||||
|
||||
data.resize(data_size);
|
||||
|
||||
Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data));
|
||||
if (!texture->compressed) {
|
||||
img->convert(real_format);
|
||||
}
|
||||
|
||||
return Ref<Image>(img);
|
||||
}
|
||||
|
||||
#ifdef GLES_OVER_GL
|
||||
|
||||
Image::Format real_format;
|
||||
|
@ -1172,9 +1294,8 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
|
|||
|
||||
glViewport(0, 0, texture->alloc_width, texture->alloc_height);
|
||||
|
||||
shaders.copy.bind();
|
||||
|
||||
shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb);
|
||||
shaders.copy.bind();
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
|
|
@ -61,19 +61,35 @@ in vec3 cube_interp;
|
|||
#else
|
||||
in vec2 uv_interp;
|
||||
#endif
|
||||
/* clang-format on */
|
||||
|
||||
#ifdef USE_ASYM_PANO
|
||||
uniform highp mat4 pano_transform;
|
||||
uniform highp vec4 asym_proj;
|
||||
#endif
|
||||
|
||||
// These definitions are here because the shader-wrapper builder does
|
||||
// not understand `#elif defined()`
|
||||
#ifdef USE_TEXTURE3D
|
||||
#endif
|
||||
#ifdef USE_TEXTURE2DARRAY
|
||||
#endif
|
||||
|
||||
#ifdef USE_CUBEMAP
|
||||
uniform samplerCube source_cube; //texunit:0
|
||||
#elif defined(USE_TEXTURE3D)
|
||||
uniform sampler3D source_3d; //texunit:0
|
||||
#elif defined(USE_TEXTURE2DARRAY)
|
||||
uniform sampler2DArray source_2d_array; //texunit:0
|
||||
#else
|
||||
uniform sampler2D source; //texunit:0
|
||||
#endif
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#if defined(USE_TEXTURE3D) || defined(USE_TEXTURE2DARRAY)
|
||||
uniform float layer;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MULTIPLIER
|
||||
uniform float multiplier;
|
||||
#endif
|
||||
|
@ -97,7 +113,6 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) {
|
|||
|
||||
#endif
|
||||
|
||||
uniform float stuff;
|
||||
uniform vec2 pixel_size;
|
||||
|
||||
in vec2 uv2_interp;
|
||||
|
@ -147,6 +162,10 @@ void main() {
|
|||
#elif defined(USE_CUBEMAP)
|
||||
vec4 color = texture(source_cube, normalize(cube_interp));
|
||||
|
||||
#elif defined(USE_TEXTURE3D)
|
||||
vec4 color = textureLod(source_3d, vec3(uv_interp, layer), 0.0);
|
||||
#elif defined(USE_TEXTURE2DARRAY)
|
||||
vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), 0.0);
|
||||
#else
|
||||
vec4 color = textureLod(source, uv_interp, 0.0);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue