mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Readback] encode signed and half-float depth texture results correctly
This commit is contained in:
@@ -138,9 +138,16 @@
|
||||
} else if (type == GL_FLOAT) {
|
||||
const Float value = needDepth ? depth[i] : static_cast<Float>(stencil[i]);
|
||||
Memcpy(dst + i * pixelBytes, &value, sizeof(value));
|
||||
} else if (type == GL_HALF_FLOAT) {
|
||||
const Uint16 value = MG_Util::EncodeFloatToHalfBits(
|
||||
needDepth ? depth[i] : static_cast<Float>(stencil[i]));
|
||||
Memcpy(dst + i * pixelBytes, &value, sizeof(value));
|
||||
} else {
|
||||
const Uint32 value = needDepth ? NormalizedDepthToUnsigned(depth[i],
|
||||
pixelBytes == 1 ? 255.0 : pixelBytes == 2 ? 65535.0 : 4294967295.0) : stencil[i];
|
||||
const Bool signedType = type == GL_BYTE || type == GL_SHORT || type == GL_INT;
|
||||
const Double maximum = signedType
|
||||
? (pixelBytes == 1 ? 127.0 : pixelBytes == 2 ? 32767.0 : 2147483647.0)
|
||||
: (pixelBytes == 1 ? 255.0 : pixelBytes == 2 ? 65535.0 : 4294967295.0);
|
||||
const Uint32 value = needDepth ? NormalizedDepthToUnsigned(depth[i], maximum) : stencil[i];
|
||||
if (pixelBytes == 1) dst[i] = static_cast<Uint8>(value);
|
||||
else if (pixelBytes == 2) { const Uint16 v = static_cast<Uint16>(value); Memcpy(dst + i * 2, &v, 2); }
|
||||
else if (pixelBytes == 4) Memcpy(dst + i * 4, &value, 4);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
SizeT size = 0;
|
||||
switch (type) {
|
||||
case GL_BYTE: case GL_UNSIGNED_BYTE: size = 1; break;
|
||||
case GL_SHORT: case GL_UNSIGNED_SHORT: size = 2; break;
|
||||
case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT: size = 2; break;
|
||||
case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: size = 4; break;
|
||||
case GL_UNSIGNED_INT_24_8: size = 4; break;
|
||||
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: size = 8; break;
|
||||
@@ -37,6 +37,10 @@
|
||||
const Float value = stencilOnly ? static_cast<Float>(s) : d;
|
||||
Memcpy(dst, &value, sizeof(value)); break;
|
||||
}
|
||||
case GL_HALF_FLOAT: {
|
||||
const Uint16 value = MG_Util::EncodeFloatToHalfBits(stencilOnly ? static_cast<Float>(s) : d);
|
||||
Memcpy(dst, &value, sizeof(value)); break;
|
||||
}
|
||||
case GL_UNSIGNED_INT_24_8: {
|
||||
Uint32 depth24 = 0;
|
||||
if (sourceFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// only checked "no GL error" would pass against a readback that never touched the buffer,
|
||||
// which is precisely how this whole cluster hid for so long.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
@@ -536,6 +537,63 @@ namespace MGITest {
|
||||
Gl().EndFrame();
|
||||
}
|
||||
|
||||
TEST_F(DepthStencilReadbackMatrixScenario, TextureDepthReadbackUsesSignedRangesAndHalfFloatEncoding) {
|
||||
if (!Ready()) return;
|
||||
DepthSource source = MakeTextureSource(GL_DEPTH_COMPONENT32F);
|
||||
ASSERT_TRUE(SourceIsUsable());
|
||||
struct Sample { float depth; GLbyte byte; GLshort shortValue; GLint intValue; GLushort halfBits; };
|
||||
const Sample samples[] = {
|
||||
{0.0f, 0, 0, 0, 0x0000},
|
||||
{0.5f, 64, 16384, 1073741824, 0x3800},
|
||||
{1.0f, 127, 32767, 2147483647, 0x3c00},
|
||||
};
|
||||
for (const auto& sample : samples) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, source.fbo);
|
||||
ClearDepthStencil(GL_DEPTH_COMPONENT32F, sample.depth, 0);
|
||||
ASSERT_EQ(FirstGLError(), 0u);
|
||||
// GPU clear, then a texture read with the source FBO unbound: neither
|
||||
// the upload shadow nor the currently bound FBO can supply the result.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, source.depthTexture);
|
||||
const auto read = [&](GLenum type, auto expected) {
|
||||
using Value = decltype(expected);
|
||||
std::vector<Value> values(static_cast<size_t>(kWidth) * kHeight, static_cast<Value>(-37));
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, type, values.data());
|
||||
EXPECT_EQ(FirstGLError(), 0u) << "depth=" << sample.depth << " type=" << type;
|
||||
const auto bad = std::count_if(values.begin(), values.end(), [&](Value value) { return value != expected; });
|
||||
EXPECT_EQ(bad, 0) << "depth=" << sample.depth << " type=" << type
|
||||
<< " first=" << static_cast<long long>(values[0])
|
||||
<< " expected=" << static_cast<long long>(expected);
|
||||
};
|
||||
read(GL_BYTE, sample.byte);
|
||||
read(GL_SHORT, sample.shortValue);
|
||||
read(GL_INT, sample.intValue);
|
||||
read(GL_HALF_FLOAT, sample.halfBits);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
DestroySource(source);
|
||||
Gl().EndFrame();
|
||||
}
|
||||
|
||||
TEST_F(DepthStencilReadbackMatrixScenario, TextureStencilHalfFloatReadbackEncodesTheIndex) {
|
||||
if (!Ready()) return;
|
||||
DepthSource source = MakeTextureSource(GL_STENCIL_INDEX8);
|
||||
ASSERT_TRUE(SourceIsUsable());
|
||||
ClearDepthStencil(GL_STENCIL_INDEX8, 0.0f, 5);
|
||||
ASSERT_EQ(FirstGLError(), 0u);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, source.depthTexture);
|
||||
std::vector<GLushort> values(static_cast<size_t>(kWidth) * kHeight, 0xdead);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, GL_HALF_FLOAT, values.data());
|
||||
EXPECT_EQ(FirstGLError(), 0u);
|
||||
// Half-float 5.0 is 0x4500. Writing the raw index 0x0005 is a different value.
|
||||
EXPECT_EQ(std::count_if(values.begin(), values.end(), [](GLushort value) { return value != 0x4500; }), 0)
|
||||
<< "first half word=" << std::hex << values[0];
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
DestroySource(source);
|
||||
Gl().EndFrame();
|
||||
}
|
||||
|
||||
// glCopyTexImage2D out of a depth attachment, then read the copy - verify_copy_tex_image.
|
||||
TEST_F(DepthStencilReadbackMatrixScenario, CopyTexImageFromADepthAttachmentSurvivesAReadBack) {
|
||||
if (!Ready()) return;
|
||||
|
||||
Reference in New Issue
Block a user