mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Fix] (DirectGLES): depth/stencil clear value and readback gaps
Three separate holes, all of them silent, that KHR-GL3x.framebuffer_blit walks straight into because it clears and reads back depth and stencil directly: - glClearStencil was frontend-only. The value was recorded in render state and never synced, so the real driver kept its default of 0 and every glClear(GL_STENCIL_BUFFER_BIT) wrote zeros. glClearColor and glClearDepthf were already synced right next to it. - Stencil readback assumed GL_STENCIL_INDEX works. It is not part of core ES (it needs GL_NV_read_stencil) and a driver without it rejects the read outright, which left the caller's buffer untouched. Where the attachment is a combined depth-stencil buffer the packed GL_DEPTH_STENCIL read carries the same bytes in its low octet, so that is now the fallback; the widening to GL_UNSIGNED_SHORT/INT moved into the same helper, since even a byte-for-byte read needs it. - Depth readback always went through GL_UNSIGNED_INT. A floating-point depth attachment (GL_DEPTH_COMPONENT32F, GL_DEPTH32F_STENCIL8 - the latter is what dEQP's own fbo-surface-type wrapper framebuffer picks) rejects that with GL_INVALID_OPERATION and only reads back as GL_FLOAT. Try both. And one format gap behind the same test: GL_DEPTH_COMPONENT32 has no ES equivalent and was being normalized to the *unsized* GL_DEPTH_COMPONENT base format, which is not a legal glTexStorage/glRenderbufferStorage internal format there - the attachment ended up with no storage and the framebuffer read back as incomplete. GL_DEPTH_COMPONENT32F is the sized ES format that keeps the requested 32-bit depth footprint; the transfer type follows it to GL_FLOAT. Takes KHR-GL3x.framebuffer_blit from 0/3 to 2/3 (the remaining multisampled_to_singlesampled_blit_color_config_test is a separate single-channel MSAA resolve issue). Note that scissor_blit additionally needs the suite to run with a depth/stencil config the test agrees with (--deqp-gl-config-name=rgba8888d24s8): under FBO surfaces the test hardcodes GL_DEPTH24_STENCIL8 for its own buffers while dEQP's wrapper framebuffer defaults to GL_DEPTH32F_STENCIL8, and blitting depth between mismatched formats is a spec error that any conformant driver has to report.
This commit is contained in:
@@ -124,6 +124,50 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
samplerParams.magFilter != SamplerFilterMode::Nearest;
|
samplerParams.magFilter != SamplerFilterMode::Nearest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frontend texture target a GLSL sampler uniform samples from. Only used to find
|
||||||
|
// which of a unit's bindings carries the GL_TEXTURE_LOD_BIAS the shader needs;
|
||||||
|
// targets with no mip chain map to Unknown so the lookup falls back to no bias.
|
||||||
|
TextureTarget SamplerUniformTextureTarget(GLenum uniformType) {
|
||||||
|
switch (uniformType) {
|
||||||
|
case GL_SAMPLER_1D:
|
||||||
|
case GL_INT_SAMPLER_1D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D:
|
||||||
|
case GL_SAMPLER_1D_SHADOW:
|
||||||
|
return TextureTarget::Texture1D;
|
||||||
|
case GL_SAMPLER_2D:
|
||||||
|
case GL_INT_SAMPLER_2D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||||
|
case GL_SAMPLER_2D_SHADOW:
|
||||||
|
return TextureTarget::Texture2D;
|
||||||
|
case GL_SAMPLER_3D:
|
||||||
|
case GL_INT_SAMPLER_3D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||||
|
return TextureTarget::Texture3D;
|
||||||
|
case GL_SAMPLER_CUBE:
|
||||||
|
case GL_INT_SAMPLER_CUBE:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||||
|
case GL_SAMPLER_CUBE_SHADOW:
|
||||||
|
return TextureTarget::TextureCubeMap;
|
||||||
|
case GL_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||||
|
return TextureTarget::Texture1DArray;
|
||||||
|
case GL_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||||
|
return TextureTarget::Texture2DArray;
|
||||||
|
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
|
||||||
|
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||||
|
return TextureTarget::TextureCubeMapArray;
|
||||||
|
default:
|
||||||
|
return TextureTarget::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Uint8* ResolveIndirectCommandBytes(const void* indirect, SizeT requiredBytes, const char* label) {
|
const Uint8* ResolveIndirectCommandBytes(const void* indirect, SizeT requiredBytes, const char* label) {
|
||||||
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
||||||
if (drawBuffer) {
|
if (drawBuffer) {
|
||||||
@@ -990,6 +1034,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (parameters.ClearDepth != g_syncedRenderStateParameters.ClearDepth) {
|
if (parameters.ClearDepth != g_syncedRenderStateParameters.ClearDepth) {
|
||||||
g_GLESFuncs.glClearDepthf(parameters.ClearDepth);
|
g_GLESFuncs.glClearDepthf(parameters.ClearDepth);
|
||||||
}
|
}
|
||||||
|
if (parameters.ClearStencil != g_syncedRenderStateParameters.ClearStencil) {
|
||||||
|
g_GLESFuncs.glClearStencil(static_cast<GLint>(parameters.ClearStencil));
|
||||||
|
}
|
||||||
if (parameters.BlendColor != g_syncedRenderStateParameters.BlendColor) {
|
if (parameters.BlendColor != g_syncedRenderStateParameters.BlendColor) {
|
||||||
const FloatVec4& blendColor = parameters.BlendColor;
|
const FloatVec4& blendColor = parameters.BlendColor;
|
||||||
g_GLESFuncs.glBlendColor(blendColor.x(), blendColor.y(), blendColor.z(), blendColor.w());
|
g_GLESFuncs.glBlendColor(blendColor.x(), blendColor.y(), blendColor.z(), blendColor.w());
|
||||||
@@ -1421,6 +1468,28 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||||
auto& samplerObject = textureUnit.GetSamplerObject();
|
auto& samplerObject = textureUnit.GetSamplerObject();
|
||||||
const auto& texture2D = textureUnit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
const auto& texture2D = textureUnit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
||||||
|
|
||||||
|
// ES has no per-texture/sampler LOD bias, so the transpiled ESSL folds
|
||||||
|
// it in from a uniform (PrgramImpl::EmulateTextureLodBias). A bound
|
||||||
|
// sampler object overrides the texture's own sampler state, as in GL.
|
||||||
|
if (samplerBinding.lodBiasLocation >= 0) {
|
||||||
|
Float lodBias = 0.0f;
|
||||||
|
if (samplerObject) {
|
||||||
|
lodBias = samplerObject->GetLodBias();
|
||||||
|
} else if (const auto sampledTarget =
|
||||||
|
SamplerUniformTextureTarget(samplerBinding.uniformType);
|
||||||
|
sampledTarget != TextureTarget::Unknown) {
|
||||||
|
const auto& boundTexture =
|
||||||
|
textureUnit.GetBindingSlot(sampledTarget).GetBoundObject();
|
||||||
|
if (boundTexture && boundTexture->GetSamplerObject()) {
|
||||||
|
lodBias = boundTexture->GetSamplerObject()->GetLodBias();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lodBias != samplerBinding.lastAssignedLodBias) {
|
||||||
|
g_GLESFuncs.glUniform1f(samplerBinding.lodBiasLocation, lodBias);
|
||||||
|
samplerBinding.lastAssignedLodBias = lodBias;
|
||||||
|
}
|
||||||
|
}
|
||||||
const SharedPtr<MG_State::GLState::SamplerObject>* rawDepthSamplerObject = &samplerObject;
|
const SharedPtr<MG_State::GLState::SamplerObject>* rawDepthSamplerObject = &samplerObject;
|
||||||
if (!*rawDepthSamplerObject && texture2D) {
|
if (!*rawDepthSamplerObject && texture2D) {
|
||||||
rawDepthSamplerObject = &texture2D->GetSamplerObject();
|
rawDepthSamplerObject = &texture2D->GetSamplerObject();
|
||||||
@@ -3311,26 +3380,46 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
|
return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool ReadPixelsDepthFloatViaUnsignedInt(GLint x, GLint y, GLsizei width, GLsizei height, void* pixels) {
|
// One normalized depth value per pixel, tightly packed. Which native read a driver
|
||||||
if (width <= 0 || height <= 0) {
|
// accepts depends on the attached format: a fixed-point depth buffer takes
|
||||||
return true;
|
// GL_UNSIGNED_INT, while a floating-point one (DEPTH_COMPONENT32F,
|
||||||
}
|
// DEPTH32F_STENCIL8 - what dEQP's own fbo-surface-type wrapper framebuffer uses)
|
||||||
|
// rejects it with GL_INVALID_OPERATION and only reads back as GL_FLOAT. Try both.
|
||||||
Vector<Uint32> raw(static_cast<SizeT>(width) * static_cast<SizeT>(height));
|
static Bool ReadDepthValuesNative(GLint x, GLint y, GLsizei width, GLsizei height, Vector<Float>& outDepth) {
|
||||||
GLenum readError = GL_NO_ERROR;
|
outDepth.assign(static_cast<SizeT>(width) * static_cast<SizeT>(height), 0.0f);
|
||||||
{
|
|
||||||
ScopedPixelPackBuffer packBuffer(0);
|
ScopedPixelPackBuffer packBuffer(0);
|
||||||
ScopedPackState packState(PixelStoreImpl::PackState{1, 0, 0, 0});
|
ScopedPackState packState(PixelStoreImpl::PackState{1, 0, 0, 0});
|
||||||
|
Vector<Uint32> raw(outDepth.size());
|
||||||
// Drain first: a stale flag some earlier best-effort call left queued
|
// Drain first: a stale flag some earlier best-effort call left queued
|
||||||
// must not be misattributed to this read (it would silently drop the
|
// must not be misattributed to this read (it would silently drop the
|
||||||
// whole readback in production builds where ErrorLopper is compiled out).
|
// whole readback in production builds where ErrorLopper is compiled out).
|
||||||
ClearGLErrors();
|
ClearGLErrors();
|
||||||
g_GLESFuncs.glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, raw.data());
|
g_GLESFuncs.glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, raw.data());
|
||||||
readError = g_GLESFuncs.glGetError();
|
if (g_GLESFuncs.glGetError() == GL_NO_ERROR) {
|
||||||
|
for (SizeT i = 0; i < outDepth.size(); ++i) {
|
||||||
|
outDepth[i] = static_cast<Float>(static_cast<Double>(raw[i]) / 4294967295.0);
|
||||||
}
|
}
|
||||||
if (readError != GL_NO_ERROR) {
|
return true;
|
||||||
MGLOG_E("ReadPixels: depth GL_FLOAT fallback read failed: %s",
|
}
|
||||||
MG_Util::ConvertGLEnumToString(readError).c_str());
|
|
||||||
|
ClearGLErrors();
|
||||||
|
g_GLESFuncs.glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, outDepth.data());
|
||||||
|
const GLenum floatError = g_GLESFuncs.glGetError();
|
||||||
|
if (floatError != GL_NO_ERROR) {
|
||||||
|
MGLOG_E("ReadPixels: neither GL_UNSIGNED_INT nor GL_FLOAT depth readback is available: %s",
|
||||||
|
MG_Util::ConvertGLEnumToString(floatError).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool ReadPixelsDepthFloatViaUnsignedInt(GLint x, GLint y, GLsizei width, GLsizei height, void* pixels) {
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Float> raw;
|
||||||
|
if (!ReadDepthValuesNative(x, y, width, height, raw)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3352,10 +3441,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
Vector<Float> rowBuf(static_cast<SizeT>(width));
|
Vector<Float> rowBuf(static_cast<SizeT>(width));
|
||||||
for (GLsizei row = 0; row < height; ++row) {
|
for (GLsizei row = 0; row < height; ++row) {
|
||||||
const Uint32* srcRow = raw.data() + static_cast<SizeT>(row) * static_cast<SizeT>(width);
|
const Float* srcRow = raw.data() + static_cast<SizeT>(row) * static_cast<SizeT>(width);
|
||||||
for (GLsizei col = 0; col < width; ++col) {
|
for (GLsizei col = 0; col < width; ++col) {
|
||||||
// TODO: preserve native depth precision when GLES exposes float depth readback directly.
|
rowBuf[col] = srcRow[col];
|
||||||
rowBuf[col] = static_cast<Float>(static_cast<Double>(srcRow[col]) / 4294967295.0);
|
|
||||||
}
|
}
|
||||||
const SizeT rowOffset = dstOffset + static_cast<SizeT>(row) * dstRowStride;
|
const SizeT rowOffset = dstOffset + static_cast<SizeT>(row) * dstRowStride;
|
||||||
if (pixelPackBufferObject) {
|
if (pixelPackBufferObject) {
|
||||||
@@ -3369,30 +3457,60 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool ReadPixelsStencilUintViaUnsignedByte(GLint x, GLint y, GLsizei width, GLsizei height, void* pixels) {
|
// One stencil byte per pixel, tightly packed. ES has no guaranteed stencil readback
|
||||||
if (width <= 0 || height <= 0) {
|
// at all: GL_STENCIL_INDEX needs GL_NV_read_stencil, and a driver without it rejects
|
||||||
return true;
|
// the read outright. Where the attachment is a combined depth-stencil buffer the
|
||||||
}
|
// packed GL_DEPTH_STENCIL read (which the packed_depth_stencil.verify_* cases already
|
||||||
|
// rely on) carries the same bytes in its low octet, so use that as the fallback.
|
||||||
Vector<Uint8> raw(static_cast<SizeT>(width) * static_cast<SizeT>(height));
|
static Bool ReadStencilBytesNative(GLint x, GLint y, GLsizei width, GLsizei height, Vector<Uint8>& outStencil) {
|
||||||
GLenum readError = GL_NO_ERROR;
|
outStencil.assign(static_cast<SizeT>(width) * static_cast<SizeT>(height), 0);
|
||||||
{
|
|
||||||
ScopedPixelPackBuffer packBuffer(0);
|
ScopedPixelPackBuffer packBuffer(0);
|
||||||
ScopedPackState packState(PixelStoreImpl::PackState{1, 0, 0, 0});
|
ScopedPackState packState(PixelStoreImpl::PackState{1, 0, 0, 0});
|
||||||
// Drain first: see ReadPixelsDepthFloatViaUnsignedInt.
|
// Drain first: see ReadPixelsDepthFloatViaUnsignedInt.
|
||||||
ClearGLErrors();
|
ClearGLErrors();
|
||||||
g_GLESFuncs.glReadPixels(x, y, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, raw.data());
|
g_GLESFuncs.glReadPixels(x, y, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, outStencil.data());
|
||||||
readError = g_GLESFuncs.glGetError();
|
if (g_GLESFuncs.glGetError() == GL_NO_ERROR) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (readError != GL_NO_ERROR) {
|
|
||||||
MGLOG_E("ReadPixels: stencil GL_UNSIGNED_INT fallback read failed: %s",
|
Vector<Uint32> packed(outStencil.size(), 0);
|
||||||
MG_Util::ConvertGLEnumToString(readError).c_str());
|
ClearGLErrors();
|
||||||
|
g_GLESFuncs.glReadPixels(x, y, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, packed.data());
|
||||||
|
const GLenum packedError = g_GLESFuncs.glGetError();
|
||||||
|
if (packedError != GL_NO_ERROR) {
|
||||||
|
MGLOG_E("ReadPixels: neither GL_STENCIL_INDEX nor GL_DEPTH_STENCIL readback is available: %s",
|
||||||
|
MG_Util::ConvertGLEnumToString(packedError).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (SizeT i = 0; i < outStencil.size(); ++i) {
|
||||||
|
outStencil[i] = static_cast<Uint8>(packed[i] & 0xFFu);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_STENCIL_INDEX readback into the client's integer layout, honouring the PACK
|
||||||
|
// pixel-store parameters. Handles the widths desktop clients ask for; the stencil
|
||||||
|
// values themselves are always 8 bits.
|
||||||
|
static Bool ReadPixelsStencilViaNative(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type,
|
||||||
|
void* pixels) {
|
||||||
|
SizeT dstPixelBytes = 0;
|
||||||
|
switch (type) {
|
||||||
|
case GL_UNSIGNED_BYTE: dstPixelBytes = sizeof(Uint8); break;
|
||||||
|
case GL_UNSIGNED_SHORT: dstPixelBytes = sizeof(Uint16); break;
|
||||||
|
case GL_UNSIGNED_INT: dstPixelBytes = sizeof(Uint32); break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Uint8> raw;
|
||||||
|
if (!ReadStencilBytesNative(x, y, width, height, raw)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
|
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
|
||||||
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
|
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
|
||||||
const SizeT dstPixelBytes = sizeof(Uint32);
|
|
||||||
const SizeT dstRowStride = AlignPixelRow(rowPixels * dstPixelBytes, packParams.Alignment);
|
const SizeT dstRowStride = AlignPixelRow(rowPixels * dstPixelBytes, packParams.Alignment);
|
||||||
const SizeT dstOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
|
const SizeT dstOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
|
||||||
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) * dstPixelBytes;
|
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) * dstPixelBytes;
|
||||||
@@ -3403,23 +3521,31 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||||
const SizeT pboOffset = reinterpret_cast<SizeT>(pixels);
|
const SizeT pboOffset = reinterpret_cast<SizeT>(pixels);
|
||||||
if (pixelPackBufferObject && pboOffset + packedSize > pixelPackBufferObject->GetSize()) {
|
if (pixelPackBufferObject && pboOffset + packedSize > pixelPackBufferObject->GetSize()) {
|
||||||
MGLOG_E("ReadPixels: stencil GL_UNSIGNED_INT fallback PBO is too small");
|
MGLOG_E("ReadPixels: stencil readback PBO is too small");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Vector<Uint32> rowBuf(static_cast<SizeT>(width));
|
const SizeT rowBytes = static_cast<SizeT>(width) * dstPixelBytes;
|
||||||
|
Vector<Uint8> rowBuf(rowBytes);
|
||||||
for (GLsizei row = 0; row < height; ++row) {
|
for (GLsizei row = 0; row < height; ++row) {
|
||||||
const Uint8* srcRow = raw.data() + static_cast<SizeT>(row) * static_cast<SizeT>(width);
|
const Uint8* srcRow = raw.data() + static_cast<SizeT>(row) * static_cast<SizeT>(width);
|
||||||
for (GLsizei col = 0; col < width; ++col) {
|
for (GLsizei col = 0; col < width; ++col) {
|
||||||
// TODO: switch to native uint stencil readback if the GLES backend exposes it.
|
switch (type) {
|
||||||
rowBuf[col] = srcRow[col];
|
case GL_UNSIGNED_BYTE:
|
||||||
|
rowBuf[static_cast<SizeT>(col)] = srcRow[col];
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
reinterpret_cast<Uint16*>(rowBuf.data())[col] = srcRow[col];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reinterpret_cast<Uint32*>(rowBuf.data())[col] = srcRow[col];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const SizeT rowOffset = dstOffset + static_cast<SizeT>(row) * dstRowStride;
|
const SizeT rowOffset = dstOffset + static_cast<SizeT>(row) * dstRowStride;
|
||||||
if (pixelPackBufferObject) {
|
if (pixelPackBufferObject) {
|
||||||
pixelPackBufferObject->WritebackFromBackend(
|
pixelPackBufferObject->WritebackFromBackend({rowBuf.data(), rowBytes}, pboOffset + rowOffset);
|
||||||
{rowBuf.data(), static_cast<SizeT>(width) * sizeof(Uint32)}, pboOffset + rowOffset);
|
|
||||||
} else if (pixels != nullptr) {
|
} else if (pixels != nullptr) {
|
||||||
Memcpy(static_cast<Uint8*>(pixels) + rowOffset, rowBuf.data(),
|
Memcpy(static_cast<Uint8*>(pixels) + rowOffset, rowBuf.data(), rowBytes);
|
||||||
static_cast<SizeT>(width) * sizeof(Uint32));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -3831,9 +3957,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("ReadPixels: finished via depth GL_FLOAT fallback");
|
MGLOG_D("ReadPixels: finished via depth GL_FLOAT fallback");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (format == GL_STENCIL_INDEX && type == GL_UNSIGNED_INT &&
|
// Every stencil read goes through the helper, not just the widening ones: ES has no
|
||||||
ReadPixelsStencilUintViaUnsignedByte(x, y, width, height, pixels)) {
|
// guaranteed GL_STENCIL_INDEX readback, so even the byte-for-byte case needs the
|
||||||
MGLOG_D("ReadPixels: finished via stencil GL_UNSIGNED_INT fallback");
|
// combined GL_DEPTH_STENCIL fallback when the driver lacks GL_NV_read_stencil.
|
||||||
|
if (format == GL_STENCIL_INDEX && ReadPixelsStencilViaNative(x, y, width, height, type, pixels)) {
|
||||||
|
MGLOG_D("ReadPixels: finished via stencil readback helper");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,13 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
|
|||||||
switch (internalFormat) {
|
switch (internalFormat) {
|
||||||
case GL_DEPTH_COMPONENT32:
|
case GL_DEPTH_COMPONENT32:
|
||||||
if (options & PixelFormatNormalizeOptionBit::NoDepthComponent32) {
|
if (options & PixelFormatNormalizeOptionBit::NoDepthComponent32) {
|
||||||
*outInternalFormat = GL_DEPTH_COMPONENT;
|
// The unsized GL_DEPTH_COMPONENT base format is not a legal
|
||||||
|
// glTexStorage/glRenderbufferStorage internal format on ES, which left
|
||||||
|
// the attachment with no storage at all (KHR-GL3x.framebuffer_blit's
|
||||||
|
// GL_DEPTH_COMPONENT32 config then read an incomplete framebuffer).
|
||||||
|
// GL_DEPTH_COMPONENT32F is the sized ES format that keeps the requested
|
||||||
|
// 32-bit depth footprint.
|
||||||
|
*outInternalFormat = GL_DEPTH_COMPONENT32F;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*outInternalFormat = internalFormat;
|
*outInternalFormat = internalFormat;
|
||||||
@@ -552,7 +558,9 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
|
|||||||
*outType = GL_UNSIGNED_INT;
|
*outType = GL_UNSIGNED_INT;
|
||||||
break;
|
break;
|
||||||
case GL_DEPTH_COMPONENT32:
|
case GL_DEPTH_COMPONENT32:
|
||||||
*outType = GL_UNSIGNED_INT;
|
// Follows the internal-format normalization above: ES only accepts
|
||||||
|
// GL_FLOAT data for a GL_DEPTH_COMPONENT32F store.
|
||||||
|
*outType = (options & PixelFormatNormalizeOptionBit::NoDepthComponent32) ? GL_FLOAT : GL_UNSIGNED_INT;
|
||||||
break;
|
break;
|
||||||
case GL_DEPTH_COMPONENT32F:
|
case GL_DEPTH_COMPONENT32F:
|
||||||
*outType = GL_FLOAT;
|
*outType = GL_FLOAT;
|
||||||
|
|||||||
Reference in New Issue
Block a user