• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes.
8 
9 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
10 
11 #include "common/bitset_utils.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/ErrorStrings.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/Surface.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/ContextImpl.h"
19 #include "libANGLE/renderer/d3d/ContextD3D.h"
20 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
21 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
22 #include "libANGLE/renderer/d3d/RendererD3D.h"
23 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
24 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
25 #include "libANGLE/renderer/d3d/TextureD3D.h"
26 
27 namespace rx
28 {
29 
30 namespace
31 {
32 
GetClearParameters(const gl::State & state,GLbitfield mask)33 ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
34 {
35     ClearParameters clearParams;
36     memset(&clearParams, 0, sizeof(ClearParameters));
37 
38     clearParams.colorF           = state.getColorClearValue();
39     clearParams.colorType        = GL_FLOAT;
40     clearParams.clearDepth       = false;
41     clearParams.depthValue       = state.getDepthClearValue();
42     clearParams.clearStencil     = false;
43     clearParams.stencilValue     = state.getStencilClearValue();
44     clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask;
45 
46     const auto *framebufferObject      = state.getDrawFramebuffer();
47     const gl::Extents &framebufferSize = framebufferObject->getFirstNonNullAttachment()->getSize();
48     const gl::Offset &surfaceTextureOffset = framebufferObject->getSurfaceTextureOffset();
49     if (state.isScissorTestEnabled())
50     {
51         clearParams.scissorEnabled = true;
52         clearParams.scissor        = state.getScissor();
53         clearParams.scissor.x      = clearParams.scissor.x + surfaceTextureOffset.x;
54         clearParams.scissor.y      = clearParams.scissor.y + surfaceTextureOffset.y;
55     }
56     else if (surfaceTextureOffset != gl::kOffsetZero)
57     {
58         clearParams.scissorEnabled = true;
59         clearParams.scissor        = gl::Rectangle(surfaceTextureOffset.x, surfaceTextureOffset.y,
60                                             framebufferSize.width, framebufferSize.height);
61     }
62 
63     const bool clearColor =
64         (mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer();
65     if (clearColor)
66     {
67         clearParams.clearColor.set();
68     }
69     else
70     {
71         clearParams.clearColor.reset();
72     }
73     clearParams.colorMask = state.getBlendStateExt().mColorMask;
74 
75     if (mask & GL_DEPTH_BUFFER_BIT)
76     {
77         if (state.getDepthStencilState().depthMask &&
78             framebufferObject->getDepthAttachment() != nullptr)
79         {
80             clearParams.clearDepth = true;
81         }
82     }
83 
84     if (mask & GL_STENCIL_BUFFER_BIT)
85     {
86         if (framebufferObject->getStencilAttachment() != nullptr &&
87             framebufferObject->getStencilAttachment()->getStencilSize() > 0)
88         {
89             clearParams.clearStencil = true;
90         }
91     }
92 
93     return clearParams;
94 }
95 }  // namespace
96 
97 ClearParameters::ClearParameters() = default;
98 
99 ClearParameters::ClearParameters(const ClearParameters &other) = default;
100 
FramebufferD3D(const gl::FramebufferState & data,RendererD3D * renderer)101 FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer)
102     : FramebufferImpl(data), mRenderer(renderer), mMockAttachment()
103 {}
104 
~FramebufferD3D()105 FramebufferD3D::~FramebufferD3D() {}
106 
clear(const gl::Context * context,GLbitfield mask)107 angle::Result FramebufferD3D::clear(const gl::Context *context, GLbitfield mask)
108 {
109     ClearParameters clearParams = GetClearParameters(context->getState(), mask);
110     return clearImpl(context, clearParams);
111 }
112 
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)113 angle::Result FramebufferD3D::clearBufferfv(const gl::Context *context,
114                                             GLenum buffer,
115                                             GLint drawbuffer,
116                                             const GLfloat *values)
117 {
118     // glClearBufferfv can be called to clear the color buffer or depth buffer
119     ClearParameters clearParams = GetClearParameters(context->getState(), 0);
120 
121     if (buffer == GL_COLOR)
122     {
123         for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
124         {
125             clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
126         }
127         clearParams.colorF    = gl::ColorF(values[0], values[1], values[2], values[3]);
128         clearParams.colorType = GL_FLOAT;
129     }
130 
131     if (buffer == GL_DEPTH)
132     {
133         clearParams.clearDepth = true;
134         clearParams.depthValue = values[0];
135     }
136 
137     return clearImpl(context, clearParams);
138 }
139 
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)140 angle::Result FramebufferD3D::clearBufferuiv(const gl::Context *context,
141                                              GLenum buffer,
142                                              GLint drawbuffer,
143                                              const GLuint *values)
144 {
145     // glClearBufferuiv can only be called to clear a color buffer
146     ClearParameters clearParams = GetClearParameters(context->getState(), 0);
147     for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
148     {
149         clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
150     }
151     clearParams.colorUI   = gl::ColorUI(values[0], values[1], values[2], values[3]);
152     clearParams.colorType = GL_UNSIGNED_INT;
153 
154     return clearImpl(context, clearParams);
155 }
156 
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)157 angle::Result FramebufferD3D::clearBufferiv(const gl::Context *context,
158                                             GLenum buffer,
159                                             GLint drawbuffer,
160                                             const GLint *values)
161 {
162     // glClearBufferiv can be called to clear the color buffer or stencil buffer
163     ClearParameters clearParams = GetClearParameters(context->getState(), 0);
164 
165     if (buffer == GL_COLOR)
166     {
167         for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
168         {
169             clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
170         }
171         clearParams.colorI    = gl::ColorI(values[0], values[1], values[2], values[3]);
172         clearParams.colorType = GL_INT;
173     }
174 
175     if (buffer == GL_STENCIL)
176     {
177         clearParams.clearStencil = true;
178         clearParams.stencilValue = values[0];
179     }
180 
181     return clearImpl(context, clearParams);
182 }
183 
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)184 angle::Result FramebufferD3D::clearBufferfi(const gl::Context *context,
185                                             GLenum buffer,
186                                             GLint drawbuffer,
187                                             GLfloat depth,
188                                             GLint stencil)
189 {
190     // glClearBufferfi can only be called to clear a depth stencil buffer
191     ClearParameters clearParams = GetClearParameters(context->getState(), 0);
192     clearParams.clearDepth      = true;
193     clearParams.depthValue      = depth;
194     clearParams.clearStencil    = true;
195     clearParams.stencilValue    = stencil;
196 
197     return clearImpl(context, clearParams);
198 }
199 
readPixels(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,const gl::PixelPackState & pack,gl::Buffer * packBuffer,void * pixels)200 angle::Result FramebufferD3D::readPixels(const gl::Context *context,
201                                          const gl::Rectangle &area,
202                                          GLenum format,
203                                          GLenum type,
204                                          const gl::PixelPackState &pack,
205                                          gl::Buffer *packBuffer,
206                                          void *pixels)
207 {
208     // Clip read area to framebuffer.
209     const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize();
210     const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
211     gl::Rectangle clippedArea;
212     if (!ClipRectangle(area, fbRect, &clippedArea))
213     {
214         // nothing to read
215         return angle::Result::Continue;
216     }
217 
218     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
219 
220     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
221 
222     GLuint outputPitch = 0;
223     ANGLE_CHECK_GL_MATH(contextD3D,
224                         sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment,
225                                                         pack.rowLength, &outputPitch));
226 
227     GLuint outputSkipBytes = 0;
228     ANGLE_CHECK_GL_MATH(contextD3D, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack,
229                                                                      false, &outputSkipBytes));
230     outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
231                        (clippedArea.y - area.y) * outputPitch;
232 
233     return readPixelsImpl(context, clippedArea, format, type, outputPitch, pack, packBuffer,
234                           static_cast<uint8_t *>(pixels) + outputSkipBytes);
235 }
236 
blit(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,GLbitfield mask,GLenum filter)237 angle::Result FramebufferD3D::blit(const gl::Context *context,
238                                    const gl::Rectangle &sourceArea,
239                                    const gl::Rectangle &destArea,
240                                    GLbitfield mask,
241                                    GLenum filter)
242 {
243     const auto &glState                      = context->getState();
244     const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer();
245     const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr;
246     ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0,
247                        (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0,
248                        filter, sourceFramebuffer));
249 
250     return angle::Result::Continue;
251 }
252 
checkStatus(const gl::Context * context) const253 gl::FramebufferStatus FramebufferD3D::checkStatus(const gl::Context *context) const
254 {
255     // if we have both a depth and stencil buffer, they must refer to the same object
256     // since we only support packed_depth_stencil and not separate depth and stencil
257     if (mState.hasSeparateDepthAndStencilAttachments())
258     {
259         return gl::FramebufferStatus::Incomplete(
260             GL_FRAMEBUFFER_UNSUPPORTED,
261             gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
262     }
263 
264     // D3D11 does not allow for overlapping RenderTargetViews.
265     // If WebGL compatibility is enabled, this has already been checked at a higher level.
266     ASSERT(!context->isWebGL() || mState.colorAttachmentsAreUniqueImages());
267     if (!context->isWebGL())
268     {
269         if (!mState.colorAttachmentsAreUniqueImages())
270         {
271             return gl::FramebufferStatus::Incomplete(
272                 GL_FRAMEBUFFER_UNSUPPORTED,
273                 gl::err::kFramebufferIncompleteUnsupportedNonUniqueAttachments);
274         }
275     }
276 
277     // D3D requires all render targets to have the same dimensions.
278     if (!mState.attachmentsHaveSameDimensions())
279     {
280         return gl::FramebufferStatus::Incomplete(
281             GL_FRAMEBUFFER_UNSUPPORTED,
282             gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions);
283     }
284 
285     return gl::FramebufferStatus::Complete();
286 }
287 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)288 angle::Result FramebufferD3D::syncState(const gl::Context *context,
289                                         GLenum binding,
290                                         const gl::Framebuffer::DirtyBits &dirtyBits,
291                                         gl::Command command)
292 {
293     if (!mColorAttachmentsForRender.valid())
294     {
295         return angle::Result::Continue;
296     }
297 
298     for (auto dirtyBit : dirtyBits)
299     {
300         if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 &&
301              dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||
302             dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS)
303         {
304             mColorAttachmentsForRender.reset();
305         }
306     }
307 
308     return angle::Result::Continue;
309 }
310 
getColorAttachmentsForRender(const gl::Context * context)311 const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context)
312 {
313     gl::DrawBufferMask activeProgramOutputs =
314         context->getState().getProgram()->getExecutable().getActiveOutputVariablesMask();
315 
316     if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs)
317     {
318         return mColorAttachmentsForRender.value();
319     }
320 
321     // Does not actually free memory
322     gl::AttachmentList colorAttachmentsForRender;
323     mColorAttachmentsForRenderMask.reset();
324 
325     const auto &colorAttachments = mState.getColorAttachments();
326     const auto &drawBufferStates = mState.getDrawBufferStates();
327     const auto &features         = mRenderer->getFeatures();
328 
329     for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex)
330     {
331         GLenum drawBufferState                           = drawBufferStates[attachmentIndex];
332         const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex];
333 
334         if (colorAttachment.isAttached() && drawBufferState != GL_NONE &&
335             activeProgramOutputs[attachmentIndex])
336         {
337             ASSERT(drawBufferState == GL_BACK ||
338                    drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
339             colorAttachmentsForRender.push_back(&colorAttachment);
340             mColorAttachmentsForRenderMask.set(attachmentIndex);
341         }
342         else if (!features.mrtPerfWorkaround.enabled)
343         {
344             colorAttachmentsForRender.push_back(nullptr);
345             mColorAttachmentsForRenderMask.set(attachmentIndex);
346         }
347     }
348 
349     // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel
350     // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel
351     // shader. We add a mock texture as render target in such case.
352     if (mRenderer->getFeatures().addMockTextureNoRenderTarget.enabled &&
353         colorAttachmentsForRender.empty() && activeProgramOutputs.any())
354     {
355         static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32,
356                       "Size of active program outputs should less or equal than 32.");
357         const GLuint activeProgramLocation = static_cast<GLuint>(
358             gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits())));
359 
360         if (mMockAttachment.isAttached() &&
361             (mMockAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation)
362         {
363             colorAttachmentsForRender.push_back(&mMockAttachment);
364         }
365         else
366         {
367             // Remove mock attachment to prevents us from leaking it, and the program may require
368             // it to be attached to a new binding point.
369             if (mMockAttachment.isAttached())
370             {
371                 mMockAttachment.detach(context, Serial());
372             }
373 
374             gl::Texture *mockTex = nullptr;
375             // TODO(jmadill): Handle error if mock texture can't be created.
376             (void)mRenderer->getIncompleteTexture(context, gl::TextureType::_2D, &mockTex);
377             if (mockTex)
378             {
379                 gl::ImageIndex index = gl::ImageIndex::Make2D(0);
380                 mMockAttachment      = gl::FramebufferAttachment(
381                     context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + activeProgramLocation, index,
382                     mockTex, Serial());
383                 colorAttachmentsForRender.push_back(&mMockAttachment);
384             }
385         }
386     }
387 
388     mColorAttachmentsForRender   = std::move(colorAttachmentsForRender);
389     mCurrentActiveProgramOutputs = activeProgramOutputs;
390 
391     return mColorAttachmentsForRender.value();
392 }
393 
destroy(const gl::Context * context)394 void FramebufferD3D::destroy(const gl::Context *context)
395 {
396     if (mMockAttachment.isAttached())
397     {
398         mMockAttachment.detach(context, Serial());
399     }
400 }
401 
402 }  // namespace rx
403