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