Implement GL_NV_read_depth_stencil.
Bug swiftshader:104
Change-Id: I9fcea0c76875de735c3bad0a5c587875d0ca4e26
Reviewed-on: https://swiftshader-review.googlesource.com/18089
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Lingfeng Yang <lfy@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index cdded3a..d169fc9 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -160,6 +160,14 @@
default: UNREACHABLE(type);
}
break;
+ case GL_STENCIL_INDEX_OES:
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE: return sw::FORMAT_S8;
+ default: UNREACHABLE(type);
+ }
+ break;
+ case GL_DEPTH_STENCIL_OES: // Cannot be read as one format. Handled separately.
default:
UNREACHABLE(format);
break;
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index fbbb356..612ee2a 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3322,9 +3322,13 @@
egl::Image *renderTarget = nullptr;
switch(format)
{
- case GL_DEPTH_COMPONENT: // GL_NV_read_depth
+ case GL_DEPTH_COMPONENT: // GL_NV_read_depth
+ case GL_DEPTH_STENCIL_OES: // GL_NV_read_depth_stencil
renderTarget = framebuffer->getDepthBuffer();
break;
+ case GL_STENCIL_INDEX_OES: // GL_NV_read_stencil
+ renderTarget = framebuffer->getStencilBuffer();
+ break;
default:
renderTarget = framebuffer->getReadRenderTarget();
break;
@@ -3339,11 +3343,64 @@
sw::SliceRect dstRect(0, 0, width, height, 0);
srcRect.clip(0.0f, 0.0f, (float)renderTarget->getWidth(), (float)renderTarget->getHeight());
- sw::Surface *externalSurface = sw::Surface::create(width, height, 1, gl::ConvertReadFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
- device->blit(renderTarget, srcRect, externalSurface, dstRect, false, false, false);
- externalSurface->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
- externalSurface->unlockExternal();
- delete externalSurface;
+ if(format != GL_DEPTH_STENCIL_OES) // The blitter only handles reading either depth or stencil.
+ {
+ sw::Surface *externalSurface = sw::Surface::create(width, height, 1, gl::ConvertReadFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
+ device->blit(renderTarget, srcRect, externalSurface, dstRect, false, false, false);
+ externalSurface->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
+ externalSurface->unlockExternal();
+ delete externalSurface;
+ }
+ else // format == GL_DEPTH_STENCIL_OES
+ {
+ ASSERT(renderTarget->getInternalFormat() == sw::FORMAT_D32F_LOCKABLE);
+ float *depth = (float*)renderTarget->lockInternal((int)srcRect.x0, (int)srcRect.y0, 0, sw::LOCK_READONLY, sw::PUBLIC);
+ uint8_t *stencil = (uint8_t*)renderTarget->lockStencil((int)srcRect.x0, (int)srcRect.y0, 0, sw::PUBLIC);
+
+ switch(type)
+ {
+ case GL_UNSIGNED_INT_24_8_OES:
+ {
+ uint32_t *output = (uint32_t*)pixels;
+
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ output[x] = ((uint32_t)roundf(depth[x] * 0xFFFFFF00) & 0xFFFFFF00) | stencil[x];
+ }
+
+ depth += renderTarget->getInternalPitchP();
+ stencil += renderTarget->getStencilPitchB();
+ (uint8_t*&)output += outputPitch;
+ }
+ }
+ break;
+ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ {
+ struct D32FS8 { float depth32f; unsigned int stencil24_8; };
+ D32FS8 *output = (D32FS8*)pixels;
+
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ output[x].depth32f = depth[x];
+ output[x].stencil24_8 = stencil[x];
+ }
+
+ depth += renderTarget->getInternalPitchP();
+ stencil += renderTarget->getStencilPitchB();
+ (uint8_t*&)output += outputPitch;
+ }
+ }
+ break;
+ default: UNREACHABLE(type);
+ }
+
+ renderTarget->unlockInternal();
+ renderTarget->unlockStencil();
+ }
renderTarget->release();
}
@@ -4441,9 +4498,12 @@
"GL_APPLE_texture_format_BGRA8888",
"GL_CHROMIUM_color_buffer_float_rgba", // A subset of EXT_color_buffer_float on top of OpenGL ES 2.0
"GL_CHROMIUM_texture_filtering_hint",
+ "GL_NV_depth_buffer_float2",
"GL_NV_fence",
"GL_NV_framebuffer_blit",
"GL_NV_read_depth",
+ "GL_NV_read_depth_stencil",
+ "GL_NV_read_stencil",
};
GLuint numExtensions = sizeof(extensions) / sizeof(extensions[0]);
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 4108a79..6ae091e 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -677,6 +677,70 @@
return true;
}
+ // GL_NV_read_depth_stencil
+ if(format == GL_DEPTH_STENCIL_OES)
+ {
+ Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
+
+ if(!depthbuffer)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+
+ GLint internalformat = depthbuffer->getFormat();
+
+ switch(type)
+ {
+ case GL_UNSIGNED_INT_24_8_OES:
+ switch(internalformat)
+ {
+ case GL_DEPTH24_STENCIL8:
+ break;
+ case GL_DEPTH32F_STENCIL8:
+ return error(GL_INVALID_OPERATION, false);
+ default:
+ UNREACHABLE(internalformat);
+ return error(GL_INVALID_OPERATION, false);
+ }
+ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ switch(internalformat)
+ {
+ case GL_DEPTH32F_STENCIL8:
+ break;
+ case GL_DEPTH24_STENCIL8:
+ return error(GL_INVALID_OPERATION, false);
+ default:
+ UNREACHABLE(internalformat);
+ return error(GL_INVALID_OPERATION, false);
+ }
+ default:
+ return error(GL_INVALID_ENUM, false);
+ }
+
+ return true;
+ }
+
+ // GL_NV_read_stencil
+ if(format == GL_STENCIL_INDEX_OES)
+ {
+ Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+
+ if(!stencilbuffer)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM, false);
+ }
+
+ return true;
+ }
+
Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer();
if(!colorbuffer)