mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 12:18:30 +09:00
[Feat] (DirectVulkan, MG_Impl): depth-stencil ReadPixels and combined-attachment queries
glReadPixels now serves GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL and GL_STENCIL_INDEX from the read framebuffer's depth/stencil attachment: per-aspect vkCmdCopyImageToBuffer copies (4-byte-aligned stencil region) with CPU repacking into GL_FLOAT / GL_UNSIGNED_SHORT / GL_UNSIGNED_INT / GL_UNSIGNED_INT_24_8 / GL_FLOAT_32_UNSIGNED_INT_24_8_REV / GL_UNSIGNED_BYTE layouts, honoring pack state and pixel-pack buffers. GL_DEPTH_STENCIL_ATTACHMENT parameter queries follow the spec's combined rules: differing depth/stencil attachment images (or a lone half) fail with GL_INVALID_OPERATION, as does GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE on the combined name. packed_depth_stencil.verify_parameters.* and verify_read_pixels.depth24_stencil8 now pass.
This commit is contained in:
@@ -6800,6 +6800,11 @@ void main() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX) {
|
||||
ReadDepthStencilPixels(*readFbo, x, y, width, height, format, type, pixels);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frame = m_frameContext.GetCurrent();
|
||||
if (!frame.isCommandRecording) {
|
||||
m_frameContext.BeginCommandRecording();
|
||||
@@ -6945,6 +6950,301 @@ void main() {
|
||||
/*applyPackImageParams=*/false);
|
||||
}
|
||||
|
||||
void VulkanRenderer::ReadDepthStencilPixels(MG_State::GLState::FramebufferObject& readFbo, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||
void* pixels) {
|
||||
if (readFbo.IsDefaultFramebuffer()) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: default framebuffer readback is unsupported");
|
||||
return;
|
||||
}
|
||||
if (width <= 0 || height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Bool wantDepth = format != GL_STENCIL_INDEX;
|
||||
const Bool wantStencil = format != GL_DEPTH_COMPONENT;
|
||||
// GL_DEPTH_STENCIL requires both halves; the state layer already rejected
|
||||
// framebuffers lacking either, so resolving via the depth attachment is enough.
|
||||
const auto attachmentType = wantDepth ? MobileGL::FramebufferAttachmentType::Depth
|
||||
: MobileGL::FramebufferAttachmentType::Stencil;
|
||||
const auto& attachment = readFbo.GetAttachment(attachmentType);
|
||||
if (!attachment.IsValid() || attachment.IsEmpty()) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: no depth/stencil attachment image");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frame = m_frameContext.GetCurrent();
|
||||
if (!frame.isCommandRecording) {
|
||||
m_frameContext.BeginCommandRecording();
|
||||
}
|
||||
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
|
||||
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
||||
}
|
||||
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkFormat vkFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageLayout* trackedLayout = nullptr;
|
||||
VkImageAspectFlags imageAspect = VK_IMAGE_ASPECT_NONE;
|
||||
Uint32 mipLevel = 0;
|
||||
Uint32 baseArrayLayer = 0;
|
||||
if (attachment.IsTexture() && attachment.GetTexture()) {
|
||||
auto textureObject = attachment.GetTexture();
|
||||
const Bool clearReady = MaterializePendingClearForTexture(frame.commandBuffer, *textureObject);
|
||||
MOBILEGL_ASSERT(clearReady, "ReadDepthStencilPixels: failed to materialize pending clear for textureId=%d",
|
||||
textureObject->GetExternalIndex());
|
||||
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*textureObject);
|
||||
if (resource == nullptr || resource->image == VK_NULL_HANDLE) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: failed to sync depth textureId=%u",
|
||||
textureObject->GetExternalIndex());
|
||||
return;
|
||||
}
|
||||
image = resource->image;
|
||||
vkFormat = resource->format;
|
||||
trackedLayout = &resource->layout;
|
||||
imageAspect = resource->aspect;
|
||||
mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
|
||||
baseArrayLayer = static_cast<Uint32>(std::max(attachment.GetTextureLayer(), 0));
|
||||
} else if (attachment.IsRenderbuffer() && attachment.GetRenderbuffer()) {
|
||||
const auto& renderbufferObject = attachment.GetRenderbuffer();
|
||||
const Bool clearReady = MaterializePendingClearForRenderbuffer(frame.commandBuffer, renderbufferObject);
|
||||
MOBILEGL_ASSERT(clearReady,
|
||||
"ReadDepthStencilPixels: failed to materialize pending clear for renderbuffer %u",
|
||||
renderbufferObject->GetExternalIndex());
|
||||
auto* resource = m_renderPassManager->GetOrCreateRenderbufferResource(renderbufferObject);
|
||||
if (resource == nullptr || resource->image == VK_NULL_HANDLE) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: failed to resolve renderbuffer %u",
|
||||
renderbufferObject->GetExternalIndex());
|
||||
return;
|
||||
}
|
||||
image = resource->image;
|
||||
vkFormat = resource->format;
|
||||
trackedLayout = &resource->layout;
|
||||
imageAspect = resource->aspect;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: source layout is undefined");
|
||||
return;
|
||||
}
|
||||
if (wantDepth && (imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) == 0) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: attachment has no depth aspect");
|
||||
return;
|
||||
}
|
||||
if (wantStencil && (imageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: attachment has no stencil aspect");
|
||||
return;
|
||||
}
|
||||
|
||||
// Per-aspect buffer-copy texel sizes (Vulkan defines the depth aspect of packed
|
||||
// formats to copy as its own tightly defined layout).
|
||||
SizeT depthCopyBytes = 0;
|
||||
switch (vkFormat) {
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
depthCopyBytes = 2;
|
||||
break;
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
depthCopyBytes = 4;
|
||||
break;
|
||||
case VK_FORMAT_S8_UINT:
|
||||
break;
|
||||
default:
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: unsupported source format=%d",
|
||||
static_cast<Int>(vkFormat));
|
||||
return;
|
||||
}
|
||||
|
||||
const SizeT pixelCount = static_cast<SizeT>(width) * static_cast<SizeT>(height);
|
||||
const VkDeviceSize depthBytes = wantDepth ? pixelCount * depthCopyBytes : 0;
|
||||
// Buffer offsets for depth/stencil copies must be 4-byte aligned.
|
||||
const VkDeviceSize stencilOffset = (depthBytes + 3) & ~VkDeviceSize{3};
|
||||
const VkDeviceSize stencilBytes = wantStencil ? pixelCount : 0;
|
||||
VkBufferObject readback;
|
||||
if (!readback.Create({
|
||||
.allocator = m_allocator,
|
||||
.size = stencilOffset + stencilBytes,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
||||
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
|
||||
})) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: failed to create readback buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
const VkImageLayout originalLayout = *trackedLayout;
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
GetImageTransitionSourceState(originalLayout, srcStageMask, srcAccessMask);
|
||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||
frame.commandBuffer, image, *trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, srcStageMask,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, imageAspect, mipLevel, 1);
|
||||
MOBILEGL_ASSERT(ok, "%s: failed to transition depth-stencil source image", __func__);
|
||||
|
||||
VkBufferImageCopy regions[2]{};
|
||||
Uint32 regionCount = 0;
|
||||
if (wantDepth) {
|
||||
auto& region = regions[regionCount++];
|
||||
region.bufferOffset = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
region.imageSubresource.mipLevel = mipLevel;
|
||||
region.imageSubresource.baseArrayLayer = baseArrayLayer;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = {x, y, 0};
|
||||
region.imageExtent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
|
||||
}
|
||||
if (wantStencil) {
|
||||
auto& region = regions[regionCount++];
|
||||
region.bufferOffset = stencilOffset;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
region.imageSubresource.mipLevel = mipLevel;
|
||||
region.imageSubresource.baseArrayLayer = baseArrayLayer;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = {x, y, 0};
|
||||
region.imageExtent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
|
||||
}
|
||||
vkCmdCopyImageToBuffer(frame.commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readback.GetHandle(),
|
||||
regionCount, regions);
|
||||
|
||||
VkPipelineStageFlags restoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags restoreAccessMask = 0;
|
||||
GetImageTransitionDestinationState(originalLayout, restoreStageMask, restoreAccessMask);
|
||||
ok = VkTextureManager::TransitionImageLayout(
|
||||
frame.commandBuffer, image, *trackedLayout, originalLayout, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
restoreStageMask, VK_ACCESS_TRANSFER_READ_BIT, restoreAccessMask, imageAspect, mipLevel, 1);
|
||||
MOBILEGL_ASSERT(ok, "%s: failed to restore depth-stencil source image layout", __func__);
|
||||
|
||||
if (!SubmitReadbackCommandsAndWait(frame)) {
|
||||
return;
|
||||
}
|
||||
const auto* mapped = static_cast<const Uint8*>(readback.Map());
|
||||
if (mapped == nullptr || !readback.Invalidate(stencilOffset + stencilBytes)) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: failed to map readback buffer");
|
||||
return;
|
||||
}
|
||||
const Uint8* depthSrc = mapped;
|
||||
const Uint8* stencilSrc = mapped + stencilOffset;
|
||||
|
||||
const auto depthValueAt = [&](SizeT i) -> Float {
|
||||
switch (vkFormat) {
|
||||
case VK_FORMAT_D16_UNORM: {
|
||||
Uint16 raw = 0;
|
||||
Memcpy(&raw, depthSrc + i * 2, sizeof(raw));
|
||||
return static_cast<Float>(raw) / 65535.0f;
|
||||
}
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: {
|
||||
Uint32 raw = 0;
|
||||
Memcpy(&raw, depthSrc + i * 4, sizeof(raw));
|
||||
return static_cast<Float>(raw & 0xFFFFFFu) / static_cast<Float>(0xFFFFFFu);
|
||||
}
|
||||
default: { // D32_SFLOAT / D32_SFLOAT_S8_UINT
|
||||
Float raw = 0.0f;
|
||||
Memcpy(&raw, depthSrc + i * 4, sizeof(raw));
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SizeT dstPixelBytes = 0;
|
||||
switch (type) {
|
||||
case GL_FLOAT:
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_24_8:
|
||||
dstPixelBytes = 4;
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
dstPixelBytes = 2;
|
||||
break;
|
||||
case GL_UNSIGNED_BYTE:
|
||||
dstPixelBytes = 1;
|
||||
break;
|
||||
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
|
||||
dstPixelBytes = 8;
|
||||
break;
|
||||
default:
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: unsupported type=0x%x", type);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<Uint8> packed(pixelCount * dstPixelBytes);
|
||||
for (SizeT i = 0; i < pixelCount; ++i) {
|
||||
Uint8* dst = packed.data() + i * dstPixelBytes;
|
||||
switch (type) {
|
||||
case GL_FLOAT: {
|
||||
const Float value = depthValueAt(i);
|
||||
Memcpy(dst, &value, sizeof(value));
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_SHORT: {
|
||||
const Uint16 value =
|
||||
static_cast<Uint16>(std::lround(static_cast<double>(depthValueAt(i)) * 65535.0));
|
||||
Memcpy(dst, &value, sizeof(value));
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT: {
|
||||
const Uint32 value = format == GL_STENCIL_INDEX
|
||||
? stencilSrc[i]
|
||||
: static_cast<Uint32>(static_cast<double>(depthValueAt(i)) * 4294967295.0);
|
||||
Memcpy(dst, &value, sizeof(value));
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_BYTE: {
|
||||
dst[0] = stencilSrc[i];
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT_24_8: {
|
||||
const Uint32 depth24 =
|
||||
static_cast<Uint32>(std::lround(static_cast<double>(depthValueAt(i)) * 16777215.0)) & 0xFFFFFFu;
|
||||
const Uint32 value = (depth24 << 8) | stencilSrc[i];
|
||||
Memcpy(dst, &value, sizeof(value));
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: {
|
||||
const Float depthValue = depthValueAt(i);
|
||||
const Uint32 stencilValue = stencilSrc[i];
|
||||
Memcpy(dst, &depthValue, sizeof(depthValue));
|
||||
Memcpy(dst + 4, &stencilValue, sizeof(stencilValue));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store honoring the client pack state (single slice).
|
||||
const auto& pixelPackBufferObject =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
|
||||
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
|
||||
const SizeT packAlignment = packParams.Alignment > 0 ? static_cast<SizeT>(packParams.Alignment) : 1;
|
||||
const SizeT dstRowStride = ((rowPixels * dstPixelBytes) + packAlignment - 1) / packAlignment * packAlignment;
|
||||
const SizeT dstSkipOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
|
||||
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) * dstPixelBytes;
|
||||
const SizeT dstRowBytes = static_cast<SizeT>(width) * dstPixelBytes;
|
||||
const SizeT pboBaseOffset = reinterpret_cast<SizeT>(pixels);
|
||||
if (pixelPackBufferObject != nullptr) {
|
||||
const SizeT requiredSize =
|
||||
pboBaseOffset + dstSkipOffset + static_cast<SizeT>(height - 1) * dstRowStride + dstRowBytes;
|
||||
if (requiredSize > pixelPackBufferObject->GetSize()) {
|
||||
MGLOG_E("DirectVulkan::ReadDepthStencilPixels skipped: pixel pack buffer is too small");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (GLsizei row = 0; row < height; ++row) {
|
||||
Uint8* srcRow = packed.data() + static_cast<SizeT>(row) * dstRowBytes;
|
||||
const SizeT dstOffset = dstSkipOffset + static_cast<SizeT>(row) * dstRowStride;
|
||||
if (pixelPackBufferObject != nullptr) {
|
||||
pixelPackBufferObject->WritebackFromBackend({srcRow, dstRowBytes}, pboBaseOffset + dstOffset);
|
||||
} else {
|
||||
Memcpy(static_cast<Uint8*>(pixels) + dstOffset, srcRow, dstRowBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderer::GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
|
||||
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
|
||||
@@ -200,6 +200,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
|
||||
void GenerateMipmap(GLenum target);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
// GL_DEPTH_COMPONENT / GL_DEPTH_STENCIL / GL_STENCIL_INDEX readback from the
|
||||
// read framebuffer's depth/stencil attachment (per-aspect buffer copies with
|
||||
// CPU repacking into the requested client layout).
|
||||
void ReadDepthStencilPixels(MG_State::GLState::FramebufferObject& readFbo, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
static SizeT GetReadbackTexelSize(VkFormat sourceFormat);
|
||||
static Bool ConvertReadbackPixels(const Uint8* sourcePixels, VkFormat sourceFormat,
|
||||
GLsizei width, GLsizei height, GLenum destinationFormat,
|
||||
|
||||
@@ -212,8 +212,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// Handles the format-derived pnames shared by GetFramebufferAttachmentParameteriv
|
||||
// and its DSA variant. Returns true when pname was one of them.
|
||||
Bool TryAnswerAttachmentFormatQuery(const MG_State::GLState::FramebufferAttachmentObject* attachmentObject,
|
||||
FramebufferAttachmentType attachmentType, GLenum pname, GLint* params,
|
||||
const char* caller) {
|
||||
FramebufferAttachmentType attachmentType, Bool depthStencilAlias,
|
||||
GLenum pname, GLint* params, const char* caller) {
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
|
||||
@@ -228,6 +228,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE && depthStencilAlias) {
|
||||
// The depth and stencil components have different types, so the combined
|
||||
// attachment name has no single answer.
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
"GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE cannot be queried on "
|
||||
"GL_DEPTH_STENCIL_ATTACHMENT."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
// With OBJECT_TYPE == GL_NONE only OBJECT_TYPE and OBJECT_NAME may be queried.
|
||||
MG_State::pGLContext->RecordError(
|
||||
@@ -579,20 +591,40 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
Bool depthStencilMismatch = false;
|
||||
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
|
||||
if (!depthStencilAlias) {
|
||||
return &framebufferObject->GetAttachment(attachmentType);
|
||||
}
|
||||
|
||||
const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth);
|
||||
if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment;
|
||||
|
||||
const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment;
|
||||
|
||||
const Bool depthLive = depthAttachment.IsValid() && !depthAttachment.IsEmpty();
|
||||
const Bool stencilLive = stencilAttachment.IsValid() && !stencilAttachment.IsEmpty();
|
||||
if (depthLive && stencilLive) {
|
||||
const Bool sameObject = depthAttachment.IsTexture() == stencilAttachment.IsTexture() &&
|
||||
(!depthAttachment.IsTexture() || depthAttachment.GetTexture() == stencilAttachment.GetTexture()) &&
|
||||
(!depthAttachment.IsRenderbuffer() ||
|
||||
depthAttachment.GetRenderbuffer() == stencilAttachment.GetRenderbuffer());
|
||||
depthStencilMismatch = !sameObject;
|
||||
} else {
|
||||
// GL_DEPTH_STENCIL_ATTACHMENT means "both halves"; a lone half does not answer it.
|
||||
depthStencilMismatch = depthLive != stencilLive;
|
||||
}
|
||||
if (depthLive) return &depthAttachment;
|
||||
if (stencilLive) return &stencilAttachment;
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
if (depthStencilMismatch) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetFramebufferAttachmentParameteriv_State",
|
||||
"GL_DEPTH_STENCIL_ATTACHMENT query with different depth and stencil "
|
||||
"attachment images."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
@@ -656,7 +688,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: GL_FALSE;
|
||||
break;
|
||||
default:
|
||||
if (TryAnswerAttachmentFormatQuery(attachmentObject, attachmentType, pname, params,
|
||||
if (TryAnswerAttachmentFormatQuery(attachmentObject, attachmentType, depthStencilAlias, pname, params,
|
||||
"GetFramebufferAttachmentParameteriv_State")) {
|
||||
return;
|
||||
}
|
||||
@@ -1623,20 +1655,40 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
|
||||
Bool depthStencilMismatch = false;
|
||||
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
|
||||
if (!depthStencilAlias) {
|
||||
return &framebufferObject->GetAttachment(attachmentType);
|
||||
}
|
||||
|
||||
const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth);
|
||||
if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment;
|
||||
|
||||
const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment;
|
||||
|
||||
const Bool depthLive = depthAttachment.IsValid() && !depthAttachment.IsEmpty();
|
||||
const Bool stencilLive = stencilAttachment.IsValid() && !stencilAttachment.IsEmpty();
|
||||
if (depthLive && stencilLive) {
|
||||
const Bool sameObject = depthAttachment.IsTexture() == stencilAttachment.IsTexture() &&
|
||||
(!depthAttachment.IsTexture() || depthAttachment.GetTexture() == stencilAttachment.GetTexture()) &&
|
||||
(!depthAttachment.IsRenderbuffer() ||
|
||||
depthAttachment.GetRenderbuffer() == stencilAttachment.GetRenderbuffer());
|
||||
depthStencilMismatch = !sameObject;
|
||||
} else {
|
||||
// GL_DEPTH_STENCIL_ATTACHMENT means "both halves"; a lone half does not answer it.
|
||||
depthStencilMismatch = depthLive != stencilLive;
|
||||
}
|
||||
if (depthLive) return &depthAttachment;
|
||||
if (stencilLive) return &stencilAttachment;
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
if (depthStencilMismatch) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"GL_DEPTH_STENCIL_ATTACHMENT query with different depth and stencil "
|
||||
"attachment images."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
@@ -1682,7 +1734,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: GL_FALSE;
|
||||
break;
|
||||
default:
|
||||
if (TryAnswerAttachmentFormatQuery(attachmentObject, attachmentType, pname, params, caller)) {
|
||||
if (TryAnswerAttachmentFormatQuery(attachmentObject, attachmentType, depthStencilAlias, pname, params,
|
||||
caller)) {
|
||||
return;
|
||||
}
|
||||
MG_State::pGLContext->RecordError(
|
||||
|
||||
Reference in New Issue
Block a user