summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
new file mode 100644
index 0000000000..5a8279a586
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
@@ -0,0 +1,402 @@
+//
+// Copyright 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes.
+
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+
+#include "common/bitset_utils.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/ErrorStrings.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/ContextImpl.h"
+#include "libANGLE/renderer/d3d/ContextD3D.h"
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/renderer/d3d/SurfaceD3D.h"
+#include "libANGLE/renderer/d3d/SwapChainD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+
+namespace rx
+{
+
+namespace
+{
+
+ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
+{
+ ClearParameters clearParams;
+ memset(&clearParams, 0, sizeof(ClearParameters));
+
+ clearParams.colorF = state.getColorClearValue();
+ clearParams.colorType = GL_FLOAT;
+ clearParams.clearDepth = false;
+ clearParams.depthValue = state.getDepthClearValue();
+ clearParams.clearStencil = false;
+ clearParams.stencilValue = state.getStencilClearValue();
+ clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask;
+
+ const auto *framebufferObject = state.getDrawFramebuffer();
+ const gl::Extents &framebufferSize = framebufferObject->getFirstNonNullAttachment()->getSize();
+ const gl::Offset &surfaceTextureOffset = framebufferObject->getSurfaceTextureOffset();
+ if (state.isScissorTestEnabled())
+ {
+ clearParams.scissorEnabled = true;
+ clearParams.scissor = state.getScissor();
+ clearParams.scissor.x = clearParams.scissor.x + surfaceTextureOffset.x;
+ clearParams.scissor.y = clearParams.scissor.y + surfaceTextureOffset.y;
+ }
+ else if (surfaceTextureOffset != gl::kOffsetZero)
+ {
+ clearParams.scissorEnabled = true;
+ clearParams.scissor = gl::Rectangle(surfaceTextureOffset.x, surfaceTextureOffset.y,
+ framebufferSize.width, framebufferSize.height);
+ }
+
+ const bool clearColor =
+ (mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer();
+ if (clearColor)
+ {
+ clearParams.clearColor.set();
+ }
+ else
+ {
+ clearParams.clearColor.reset();
+ }
+ clearParams.colorMask = state.getBlendStateExt().getColorMaskBits();
+
+ if (mask & GL_DEPTH_BUFFER_BIT)
+ {
+ if (state.getDepthStencilState().depthMask &&
+ framebufferObject->getDepthAttachment() != nullptr)
+ {
+ clearParams.clearDepth = true;
+ }
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT)
+ {
+ if (framebufferObject->getStencilAttachment() != nullptr &&
+ framebufferObject->getStencilAttachment()->getStencilSize() > 0)
+ {
+ clearParams.clearStencil = true;
+ }
+ }
+
+ return clearParams;
+}
+} // namespace
+
+ClearParameters::ClearParameters() = default;
+
+ClearParameters::ClearParameters(const ClearParameters &other) = default;
+
+FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer)
+ : FramebufferImpl(data), mRenderer(renderer), mMockAttachment()
+{}
+
+FramebufferD3D::~FramebufferD3D() {}
+
+angle::Result FramebufferD3D::clear(const gl::Context *context, GLbitfield mask)
+{
+ ClearParameters clearParams = GetClearParameters(context->getState(), mask);
+ return clearImpl(context, clearParams);
+}
+
+angle::Result FramebufferD3D::clearBufferfv(const gl::Context *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values)
+{
+ // glClearBufferfv can be called to clear the color buffer or depth buffer
+ ClearParameters clearParams = GetClearParameters(context->getState(), 0);
+
+ if (buffer == GL_COLOR)
+ {
+ for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
+ {
+ clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+ }
+ clearParams.colorF = gl::ColorF(values[0], values[1], values[2], values[3]);
+ clearParams.colorType = GL_FLOAT;
+ }
+
+ if (buffer == GL_DEPTH)
+ {
+ clearParams.clearDepth = true;
+ clearParams.depthValue = values[0];
+ }
+
+ return clearImpl(context, clearParams);
+}
+
+angle::Result FramebufferD3D::clearBufferuiv(const gl::Context *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values)
+{
+ // glClearBufferuiv can only be called to clear a color buffer
+ ClearParameters clearParams = GetClearParameters(context->getState(), 0);
+ for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
+ {
+ clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+ }
+ clearParams.colorUI = gl::ColorUI(values[0], values[1], values[2], values[3]);
+ clearParams.colorType = GL_UNSIGNED_INT;
+
+ return clearImpl(context, clearParams);
+}
+
+angle::Result FramebufferD3D::clearBufferiv(const gl::Context *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *values)
+{
+ // glClearBufferiv can be called to clear the color buffer or stencil buffer
+ ClearParameters clearParams = GetClearParameters(context->getState(), 0);
+
+ if (buffer == GL_COLOR)
+ {
+ for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
+ {
+ clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+ }
+ clearParams.colorI = gl::ColorI(values[0], values[1], values[2], values[3]);
+ clearParams.colorType = GL_INT;
+ }
+
+ if (buffer == GL_STENCIL)
+ {
+ clearParams.clearStencil = true;
+ clearParams.stencilValue = values[0];
+ }
+
+ return clearImpl(context, clearParams);
+}
+
+angle::Result FramebufferD3D::clearBufferfi(const gl::Context *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil)
+{
+ // glClearBufferfi can only be called to clear a depth stencil buffer
+ ClearParameters clearParams = GetClearParameters(context->getState(), 0);
+ clearParams.clearDepth = true;
+ clearParams.depthValue = depth;
+ clearParams.clearStencil = true;
+ clearParams.stencilValue = stencil;
+
+ return clearImpl(context, clearParams);
+}
+
+angle::Result FramebufferD3D::readPixels(const gl::Context *context,
+ const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ const gl::PixelPackState &pack,
+ gl::Buffer *packBuffer,
+ void *pixels)
+{
+ // Clip read area to framebuffer.
+ const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize();
+ const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
+ gl::Rectangle clippedArea;
+ if (!ClipRectangle(area, fbRect, &clippedArea))
+ {
+ // nothing to read
+ return angle::Result::Continue;
+ }
+
+ const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
+
+ ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
+
+ GLuint outputPitch = 0;
+ ANGLE_CHECK_GL_MATH(contextD3D,
+ sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment,
+ pack.rowLength, &outputPitch));
+
+ GLuint outputSkipBytes = 0;
+ ANGLE_CHECK_GL_MATH(contextD3D, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack,
+ false, &outputSkipBytes));
+ outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
+ (clippedArea.y - area.y) * outputPitch;
+
+ return readPixelsImpl(context, clippedArea, format, type, outputPitch, pack, packBuffer,
+ static_cast<uint8_t *>(pixels) + outputSkipBytes);
+}
+
+angle::Result FramebufferD3D::blit(const gl::Context *context,
+ const gl::Rectangle &sourceArea,
+ const gl::Rectangle &destArea,
+ GLbitfield mask,
+ GLenum filter)
+{
+ const auto &glState = context->getState();
+ const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer();
+ const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr;
+ ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0,
+ (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0,
+ filter, sourceFramebuffer));
+
+ return angle::Result::Continue;
+}
+
+gl::FramebufferStatus FramebufferD3D::checkStatus(const gl::Context *context) const
+{
+ // if we have both a depth and stencil buffer, they must refer to the same object
+ // since we only support packed_depth_stencil and not separate depth and stencil
+ if (mState.hasSeparateDepthAndStencilAttachments())
+ {
+ return gl::FramebufferStatus::Incomplete(
+ GL_FRAMEBUFFER_UNSUPPORTED,
+ gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
+ }
+
+ // D3D11 does not allow for overlapping RenderTargetViews.
+ // If WebGL compatibility is enabled, this has already been checked at a higher level.
+ ASSERT(!context->isWebGL() || mState.colorAttachmentsAreUniqueImages());
+ if (!context->isWebGL())
+ {
+ if (!mState.colorAttachmentsAreUniqueImages())
+ {
+ return gl::FramebufferStatus::Incomplete(
+ GL_FRAMEBUFFER_UNSUPPORTED,
+ gl::err::kFramebufferIncompleteUnsupportedNonUniqueAttachments);
+ }
+ }
+
+ // D3D requires all render targets to have the same dimensions.
+ if (!mState.attachmentsHaveSameDimensions())
+ {
+ return gl::FramebufferStatus::Incomplete(
+ GL_FRAMEBUFFER_UNSUPPORTED,
+ gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions);
+ }
+
+ return gl::FramebufferStatus::Complete();
+}
+
+angle::Result FramebufferD3D::syncState(const gl::Context *context,
+ GLenum binding,
+ const gl::Framebuffer::DirtyBits &dirtyBits,
+ gl::Command command)
+{
+ if (!mColorAttachmentsForRender.valid())
+ {
+ return angle::Result::Continue;
+ }
+
+ for (auto dirtyBit : dirtyBits)
+ {
+ if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 &&
+ dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||
+ dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS)
+ {
+ mColorAttachmentsForRender.reset();
+ }
+ }
+
+ return angle::Result::Continue;
+}
+
+const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context)
+{
+ gl::DrawBufferMask activeProgramOutputs =
+ context->getState().getProgram()->getExecutable().getActiveOutputVariablesMask();
+
+ if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs)
+ {
+ return mColorAttachmentsForRender.value();
+ }
+
+ // Does not actually free memory
+ gl::AttachmentList colorAttachmentsForRender;
+ mColorAttachmentsForRenderMask.reset();
+
+ const auto &colorAttachments = mState.getColorAttachments();
+ const auto &drawBufferStates = mState.getDrawBufferStates();
+ const auto &features = mRenderer->getFeatures();
+
+ for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex)
+ {
+ GLenum drawBufferState = drawBufferStates[attachmentIndex];
+ const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex];
+
+ if (colorAttachment.isAttached() && drawBufferState != GL_NONE &&
+ activeProgramOutputs[attachmentIndex])
+ {
+ ASSERT(drawBufferState == GL_BACK ||
+ drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
+ colorAttachmentsForRender.push_back(&colorAttachment);
+ mColorAttachmentsForRenderMask.set(attachmentIndex);
+ }
+ else if (!features.mrtPerfWorkaround.enabled)
+ {
+ colorAttachmentsForRender.push_back(nullptr);
+ mColorAttachmentsForRenderMask.set(attachmentIndex);
+ }
+ }
+
+ // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel
+ // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel
+ // shader. We add a mock texture as render target in such case.
+ if (mRenderer->getFeatures().addMockTextureNoRenderTarget.enabled &&
+ colorAttachmentsForRender.empty() && activeProgramOutputs.any())
+ {
+ static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32,
+ "Size of active program outputs should less or equal than 32.");
+ const GLuint activeProgramLocation = static_cast<GLuint>(
+ gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits())));
+
+ if (mMockAttachment.isAttached() &&
+ (mMockAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation)
+ {
+ colorAttachmentsForRender.push_back(&mMockAttachment);
+ }
+ else
+ {
+ // Remove mock attachment to prevents us from leaking it, and the program may require
+ // it to be attached to a new binding point.
+ if (mMockAttachment.isAttached())
+ {
+ mMockAttachment.detach(context, Serial());
+ }
+
+ gl::Texture *mockTex = nullptr;
+ // TODO(jmadill): Handle error if mock texture can't be created.
+ (void)mRenderer->getIncompleteTexture(context, gl::TextureType::_2D, &mockTex);
+ if (mockTex)
+ {
+ gl::ImageIndex index = gl::ImageIndex::Make2D(0);
+ mMockAttachment = gl::FramebufferAttachment(
+ context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + activeProgramLocation, index,
+ mockTex, Serial());
+ colorAttachmentsForRender.push_back(&mMockAttachment);
+ }
+ }
+ }
+
+ mColorAttachmentsForRender = std::move(colorAttachmentsForRender);
+ mCurrentActiveProgramOutputs = activeProgramOutputs;
+
+ return mColorAttachmentsForRender.value();
+}
+
+void FramebufferD3D::destroy(const gl::Context *context)
+{
+ if (mMockAttachment.isAttached())
+ {
+ mMockAttachment.detach(context, Serial());
+ }
+}
+
+} // namespace rx