Commit edc0d2ee by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Disallow loadOp=LOAD for MSRTT depth/stencil textures

EXT_multisampled_render_buffer2 specifies that depth/stencil textures are expected to be in a perpetual state of invalidated, except during rendering. This change makes sure that they never use loadOp=LOAD. Additionally fixes a bug where clears applied to MSRTT depth/stencil textures didn't take effect because they were applied to the multisampled image (since the resolved image was not given to the render target). Bug: angleproject:4836 Bug: angleproject:5063 Change-Id: I4506f4de415dca6c222111a1ae62017d2fb1e2b1 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2412848 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent bdecaf33
...@@ -2242,6 +2242,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2242,6 +2242,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
// Color render targets are never entirely transient. Only depth/stencil
// multisampled-render-to-texture textures can be so.
ASSERT(!colorRenderTarget->isEntirelyTransient());
renderPassAttachmentOps.setLayouts(colorIndexVk, vk::ImageLayout::ColorAttachment, renderPassAttachmentOps.setLayouts(colorIndexVk, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
...@@ -2258,11 +2262,11 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2258,11 +2262,11 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
} }
else else
{ {
renderPassAttachmentOps.setOps(colorIndexVk, const VkAttachmentLoadOp loadOp = colorRenderTarget->hasDefinedContent()
colorRenderTarget->hasDefinedContent() ? VK_ATTACHMENT_LOAD_OP_LOAD
? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
storeOp); renderPassAttachmentOps.setOps(colorIndexVk, loadOp, storeOp);
packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT, packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT,
kUninitializedClearValue); kUninitializedClearValue);
} }
...@@ -2309,8 +2313,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2309,8 +2313,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// no resolve attachment, there's no data to load. The latter is the case with // no resolve attachment, there's no data to load. The latter is the case with
// depth/stencil texture attachments per GL_EXT_multisampled_render_to_texture2. // depth/stencil texture attachments per GL_EXT_multisampled_render_to_texture2.
if (!depthStencilRenderTarget->hasDefinedContent() || if (!depthStencilRenderTarget->hasDefinedContent() ||
(depthStencilRenderTarget->isImageTransient() && depthStencilRenderTarget->isEntirelyTransient())
!depthStencilRenderTarget->hasResolveAttachment()))
{ {
depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
......
...@@ -43,7 +43,7 @@ void RenderTargetVk::init(vk::ImageHelper *image, ...@@ -43,7 +43,7 @@ void RenderTargetVk::init(vk::ImageHelper *image,
vk::ImageViewHelper *resolveImageViews, vk::ImageViewHelper *resolveImageViews,
gl::LevelIndex levelIndexGL, gl::LevelIndex levelIndexGL,
uint32_t layerIndex, uint32_t layerIndex,
bool isImageTransient) RenderTargetTransience transience)
{ {
mImage = image; mImage = image;
mImageViews = imageViews; mImageViews = imageViews;
...@@ -55,7 +55,7 @@ void RenderTargetVk::init(vk::ImageHelper *image, ...@@ -55,7 +55,7 @@ void RenderTargetVk::init(vk::ImageHelper *image,
// Conservatively assume the content is defined. // Conservatively assume the content is defined.
mContentDefined = true; mContentDefined = true;
mIsImageTransient = isImageTransient; mTransience = transience;
} }
void RenderTargetVk::reset() void RenderTargetVk::reset()
...@@ -189,7 +189,7 @@ bool RenderTargetVk::isResolveImageOwnerOfData() const ...@@ -189,7 +189,7 @@ bool RenderTargetVk::isResolveImageOwnerOfData() const
// If there's a resolve attachment and the image itself is transient, it's the resolve // If there's a resolve attachment and the image itself is transient, it's the resolve
// attachment that owns the data, so all non-render-pass accesses to the render target data // attachment that owns the data, so all non-render-pass accesses to the render target data
// should go through the resolve attachment. // should go through the resolve attachment.
return hasResolveAttachment() && isImageTransient(); return isImageTransient();
} }
angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk, angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk,
......
...@@ -30,6 +30,17 @@ class RenderPassDesc; ...@@ -30,6 +30,17 @@ class RenderPassDesc;
class ContextVk; class ContextVk;
class TextureVk; class TextureVk;
enum class RenderTargetTransience
{
// Regular render targets that load and store from the image.
Default,
// Multisampled-render-to-texture textures, where the implicit multisampled image is transient,
// but the resolved image is persistent.
MultisampledTransient,
// Multisampled-render-to-texture depth/stencil textures.
EntirelyTransient,
};
// This is a very light-weight class that does not own to the resources it points to. // This is a very light-weight class that does not own to the resources it points to.
// It's meant only to copy across some information from a FramebufferAttachment to the // It's meant only to copy across some information from a FramebufferAttachment to the
// business rendering logic. It stores Images and ImageViews by pointer for performance. // business rendering logic. It stores Images and ImageViews by pointer for performance.
...@@ -48,7 +59,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -48,7 +59,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
vk::ImageViewHelper *resolveImageViews, vk::ImageViewHelper *resolveImageViews,
gl::LevelIndex levelIndexGL, gl::LevelIndex levelIndexGL,
uint32_t layerIndex, uint32_t layerIndex,
bool isImageTransient); RenderTargetTransience transience);
void reset(); void reset();
vk::ImageViewSubresourceSerial getDrawSubresourceSerial() const; vk::ImageViewSubresourceSerial getDrawSubresourceSerial() const;
...@@ -103,10 +114,13 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -103,10 +114,13 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void invalidateEntireContent() { mContentDefined = false; } void invalidateEntireContent() { mContentDefined = false; }
void restoreEntireContent() { mContentDefined = true; } void restoreEntireContent() { mContentDefined = true; }
// See the description of mIsImageTransient for details of how the following two can // See the description of mTransience for details of how the following two can interact.
// interact.
bool hasResolveAttachment() const { return mResolveImage != nullptr; } bool hasResolveAttachment() const { return mResolveImage != nullptr; }
bool isImageTransient() const { return mIsImageTransient; } bool isImageTransient() const { return mTransience != RenderTargetTransience::Default; }
bool isEntirelyTransient() const
{
return mTransience == RenderTargetTransience::EntirelyTransient;
}
private: private:
angle::Result getImageViewImpl(ContextVk *contextVk, angle::Result getImageViewImpl(ContextVk *contextVk,
...@@ -140,36 +154,44 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -140,36 +154,44 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// loadOp of this attachment. // loadOp of this attachment.
bool mContentDefined; bool mContentDefined;
// If resolve attachment exists, |mIsImageTransient| is true if the multisampled results need to // If resolve attachment exists, |mTransience| could be *Transient if the multisampled results
// be discarded. // need to be discarded.
// //
// - GL_EXT_multisampled_render_to_texture: this is true for render targets created for this // - GL_EXT_multisampled_render_to_texture[2]: this is |MultisampledTransient| for render
// extension's usage. Only color attachments use this optimization at the moment. // targets created from color textures, as well as color or depth/stencil renderbuffers.
// - GL_EXT_multisampled_render_to_texture2: this is true for depth/stencil textures per this // - GL_EXT_multisampled_render_to_texture2: this is |EntirelyTransient| for depth/stencil
// extension, even though a resolve attachment is not even provided. // textures per this extension, even though a resolve attachment is not even provided.
// - Multisampled swapchain: TODO(syoussefi) this is true for the multisampled color attachment.
// http://anglebug.com/4836
// //
// Based on the above, we have: // Based on the above, we have:
// //
// mResolveImage == nullptr | mResolveImage != nullptr // mResolveImage == nullptr
// | // Normal rendering
// Normal rendering | Invalid // Default No resolve
// !IsTransient No resolve | // storeOp = STORE
// storeOp = STORE | // Owner of data: mImage
// Owner of data: mImage | //
// | // ---------------------------------------------
// ---------------------------------------------+--------------------------------------- //
// | // mResolveImage != nullptr
// EXT_multisampled_render_to_texture2 | GL_EXT_multisampled_render_to_texture // GL_EXT_multisampled_render_to_texture
// | or multisampled Swapchain optimization // Multisampled Resolve
// IsTransient No resolve | Resolve // Transient storeOp = DONT_CARE
// storeOp = DONT_CARE | storeOp = DONT_CARE // resolve storeOp = STORE
// Owner of data: None (not stored) | Owner of data: mResolveImage // Owner of data: mResolveImage
//
// ---------------------------------------------
//
// mResolveImage != nullptr
// GL_EXT_multisampled_render_to_texture2
// Entirely No Resolve
// Transient storeOp = DONT_CARE
// Owner of data: mResolveImage
// //
// In the above, storeOp of the resolve attachment is always STORE. if !IsTransient, storeOp is // In the above, storeOp of the resolve attachment is always STORE. If |Default|, storeOp is
// affected by a framebuffer invalidate call. // affected by a framebuffer invalidate call. Note that even though |EntirelyTransient| has a
bool mIsImageTransient; // resolve attachment, it is not used. The only purpose of |mResolveImage| is to store deferred
// clears.
RenderTargetTransience mTransience;
}; };
// A vector of rendertargets // A vector of rendertargets
......
...@@ -112,11 +112,12 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context, ...@@ -112,11 +112,12 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
contextVk, renderer->getMemoryProperties(), gl::TextureType::_2D, samples, *mImage)); contextVk, renderer->getMemoryProperties(), gl::TextureType::_2D, samples, *mImage));
mRenderTarget.init(&mMultisampledImage, &mMultisampledImageViews, mImage, &mImageViews, mRenderTarget.init(&mMultisampledImage, &mMultisampledImageViews, mImage, &mImageViews,
gl::LevelIndex(0), 0, true); gl::LevelIndex(0), 0, RenderTargetTransience::MultisampledTransient);
} }
else else
{ {
mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, gl::LevelIndex(0), 0, false); mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, gl::LevelIndex(0), 0,
RenderTargetTransience::Default);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -178,7 +179,7 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex ...@@ -178,7 +179,7 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
} }
mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, imageVk->getImageLevel(), mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, imageVk->getImageLevel(),
imageVk->getImageLayer(), false); imageVk->getImageLayer(), RenderTargetTransience::Default);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -240,10 +240,10 @@ OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, Re ...@@ -240,10 +240,10 @@ OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, Re
mDepthStencilAttachment(this) mDepthStencilAttachment(this)
{ {
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr, mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image, mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
&mDepthStencilAttachment.imageViews, nullptr, nullptr, &mDepthStencilAttachment.imageViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
} }
OffscreenSurfaceVk::~OffscreenSurfaceVk() {} OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
...@@ -270,7 +270,7 @@ angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk) ...@@ -270,7 +270,7 @@ angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
ANGLE_TRY(mColorAttachment.initialize( ANGLE_TRY(mColorAttachment.initialize(
displayVk, mWidth, mHeight, renderer->getFormat(config->renderTargetFormat), samples)); displayVk, mWidth, mHeight, renderer->getFormat(config->renderTargetFormat), samples));
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr,
nullptr, gl::LevelIndex(0), 0, false); nullptr, gl::LevelIndex(0), 0, RenderTargetTransience::Default);
} }
if (config->depthStencilFormat != GL_NONE) if (config->depthStencilFormat != GL_NONE)
...@@ -279,7 +279,7 @@ angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk) ...@@ -279,7 +279,7 @@ angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples)); displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples));
mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image, mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
&mDepthStencilAttachment.imageViews, nullptr, nullptr, &mDepthStencilAttachment.imageViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -483,9 +483,9 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ ...@@ -483,9 +483,9 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ
// Initialize the color render target with the multisampled targets. If not multisampled, the // Initialize the color render target with the multisampled targets. If not multisampled, the
// render target will be updated to refer to a swapchain image on every acquire. // render target will be updated to refer to a swapchain image on every acquire.
mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr, mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr, nullptr, mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
mDepthStencilImageBinding.bind(&mDepthStencilImage); mDepthStencilImageBinding.bind(&mDepthStencilImage);
mColorImageMSBinding.bind(&mColorImageMS); mColorImageMSBinding.bind(&mColorImageMS);
} }
...@@ -969,7 +969,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, ...@@ -969,7 +969,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
// Initialize the color render target with the multisampled targets. If not multisampled, // Initialize the color render target with the multisampled targets. If not multisampled,
// the render target will be updated to refer to a swapchain image on every acquire. // the render target will be updated to refer to a swapchain image on every acquire.
mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr, mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
} }
ANGLE_TRY(resizeSwapchainImages(context, imageCount)); ANGLE_TRY(resizeSwapchainImages(context, imageCount));
...@@ -995,7 +995,8 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, ...@@ -995,7 +995,8 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr, mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr,
nullptr, gl::LevelIndex(0), 0, false); nullptr, gl::LevelIndex(0), 0,
RenderTargetTransience::Default);
// We will need to pass depth/stencil image views to the RenderTargetVk in the future. // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
} }
......
...@@ -2001,6 +2001,9 @@ angle::Result TextureVk::initRenderTargets(ContextVk *contextVk, ...@@ -2001,6 +2001,9 @@ angle::Result TextureVk::initRenderTargets(ContextVk *contextVk,
const bool isMultisampledRenderToTexture = const bool isMultisampledRenderToTexture =
renderToTextureIndex != gl::RenderToTextureImageIndex::Default; renderToTextureIndex != gl::RenderToTextureImageIndex::Default;
RenderTargetTransience transience = isMultisampledRenderToTexture
? RenderTargetTransience::MultisampledTransient
: RenderTargetTransience::Default;
// If multisampled render to texture, use the multisampled image as draw image instead, and // If multisampled render to texture, use the multisampled image as draw image instead, and
// resolve into the texture's image automatically. // resolve into the texture's image automatically.
...@@ -2014,20 +2017,17 @@ angle::Result TextureVk::initRenderTargets(ContextVk *contextVk, ...@@ -2014,20 +2017,17 @@ angle::Result TextureVk::initRenderTargets(ContextVk *contextVk,
drawImageViews = &mMultisampledImageViews[renderToTextureIndex]; drawImageViews = &mMultisampledImageViews[renderToTextureIndex];
// If the texture is depth/stencil, GL_EXT_multisampled_render_to_texture2 explicitly // If the texture is depth/stencil, GL_EXT_multisampled_render_to_texture2 explicitly
// indicates that there is no need for the image to be resolved. In that case, don't // indicates that there is no need for the image to be resolved. In that case, mark the
// specify the resolve image. Note that the multisampled image's data is discarded // render target as entirely transient.
// nevertheless per this spec.
if (mImage->getAspectFlags() != VK_IMAGE_ASPECT_COLOR_BIT) if (mImage->getAspectFlags() != VK_IMAGE_ASPECT_COLOR_BIT)
{ {
resolveImage = nullptr; transience = RenderTargetTransience::EntirelyTransient;
resolveImageViews = nullptr;
} }
} }
renderTargets[layerIndex].init(drawImage, drawImageViews, resolveImage, resolveImageViews, renderTargets[layerIndex].init(drawImage, drawImageViews, resolveImage, resolveImageViews,
getNativeImageLevel(levelIndex), getNativeImageLevel(levelIndex),
getNativeImageLayer(layerIndex), getNativeImageLayer(layerIndex), transience);
isMultisampledRenderToTexture);
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -119,7 +119,7 @@ angle::Result IOSurfaceSurfaceVkMac::initializeImpl(DisplayVk *displayVk) ...@@ -119,7 +119,7 @@ angle::Result IOSurfaceSurfaceVkMac::initializeImpl(DisplayVk *displayVk)
renderer->getFormat(kIOSurfaceFormats[mFormatIndex].nativeSizedInternalFormat), samples, renderer->getFormat(kIOSurfaceFormats[mFormatIndex].nativeSizedInternalFormat), samples,
IOSurfaceGetBaseAddressOfPlane(mIOSurface, mPlane))); IOSurfaceGetBaseAddressOfPlane(mIOSurface, mPlane)));
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr, mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr,
gl::LevelIndex(0), 0, false); gl::LevelIndex(0), 0, RenderTargetTransience::Default);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -105,6 +105,9 @@ class DepthStencilTest : public ANGLETest ...@@ -105,6 +105,9 @@ class DepthStencilTest : public ANGLETest
bool mHasStencil = true; bool mHasStencil = true;
}; };
class DepthStencilTestES3 : public DepthStencilTest
{};
void DepthStencilTest::ensureColor(GLColor color) void DepthStencilTest::ensureColor(GLColor color)
{ {
const int width = getWindowWidth(); const int width = getWindowWidth();
...@@ -251,6 +254,62 @@ TEST_P(DepthStencilTest, StencilOnlyEmulatedWithPacked) ...@@ -251,6 +254,62 @@ TEST_P(DepthStencilTest, StencilOnlyEmulatedWithPacked)
ensureDepthUnaffected(); ensureDepthUnaffected();
} }
// Tests that clearing depth/stencil followed by draw works when the depth/stencil attachment is a
// texture.
TEST_P(DepthStencilTestES3, ClearThenDraw)
{
GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
constexpr GLsizei kSize = 6;
// Create framebuffer to draw into, with both color and depth attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLTexture depth;
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8_OES, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
ASSERT_GL_NO_ERROR();
// Set viewport and clear depth/stencil
glViewport(0, 0, kSize, kSize);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not clear to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
// Draw red
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red);
}
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(DepthStencilTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(DepthStencilTest);
ANGLE_INSTANTIATE_TEST_ES3(DepthStencilTestES3);
} // anonymous namespace } // anonymous namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment