blob: 69e350512b32039f194de8821be1c91df4fac12a [file] [log] [blame]
Geoff Lang6a1e6b92014-11-06 10:42:45 -05001//
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
Geoff Langda88add2014-12-01 10:22:01 -05007// FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes.
Geoff Lang6a1e6b92014-11-06 10:42:45 -05008
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/renderer/d3d/FramebufferD3D.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050010#include "libANGLE/renderer/d3d/TextureD3D.h"
Geoff Langda88add2014-12-01 10:22:01 -050011#include "libANGLE/renderer/d3d/RendererD3D.h"
Geoff Langc2e75af2015-01-05 14:26:24 -050012#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050013#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
Geoff Langbce529e2014-12-01 12:48:41 -050014#include "libANGLE/formatutils.h"
Geoff Lang54bd5a42014-12-01 12:51:04 -050015#include "libANGLE/Framebuffer.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050016#include "libANGLE/FramebufferAttachment.h"
Geoff Lang6a1e6b92014-11-06 10:42:45 -050017
18namespace rx
19{
20
Geoff Langc2e75af2015-01-05 14:26:24 -050021DefaultAttachmentD3D::DefaultAttachmentD3D(RenderTargetD3D *renderTarget)
Geoff Lang6a1e6b92014-11-06 10:42:45 -050022 : mRenderTarget(renderTarget)
23{
24 ASSERT(mRenderTarget);
25}
26
27DefaultAttachmentD3D::~DefaultAttachmentD3D()
28{
29 SafeDelete(mRenderTarget);
30}
31
32DefaultAttachmentD3D *DefaultAttachmentD3D::makeDefaultAttachmentD3D(DefaultAttachmentImpl* impl)
33{
34 ASSERT(HAS_DYNAMIC_TYPE(DefaultAttachmentD3D*, impl));
35 return static_cast<DefaultAttachmentD3D*>(impl);
36}
37
38GLsizei DefaultAttachmentD3D::getWidth() const
39{
40 return mRenderTarget->getWidth();
41}
42
43GLsizei DefaultAttachmentD3D::getHeight() const
44{
45 return mRenderTarget->getHeight();
46}
47
48GLenum DefaultAttachmentD3D::getInternalFormat() const
49{
50 return mRenderTarget->getInternalFormat();
51}
52
Geoff Lang6a1e6b92014-11-06 10:42:45 -050053GLsizei DefaultAttachmentD3D::getSamples() const
54{
55 return mRenderTarget->getSamples();
56}
57
Geoff Langc2e75af2015-01-05 14:26:24 -050058RenderTargetD3D *DefaultAttachmentD3D::getRenderTarget() const
Geoff Lang6a1e6b92014-11-06 10:42:45 -050059{
60 return mRenderTarget;
61}
62
Geoff Langda88add2014-12-01 10:22:01 -050063
64FramebufferD3D::FramebufferD3D(RendererD3D *renderer)
Geoff Lang748f74e2014-12-01 11:25:34 -050065 : mRenderer(renderer),
Geoff Langb04dc822014-12-01 12:02:02 -050066 mColorBuffers(renderer->getRendererCaps().maxColorAttachments),
67 mDepthbuffer(nullptr),
68 mStencilbuffer(nullptr),
Geoff Langbce529e2014-12-01 12:48:41 -050069 mDrawBuffers(renderer->getRendererCaps().maxDrawBuffers),
70 mReadBuffer(GL_COLOR_ATTACHMENT0)
Geoff Langda88add2014-12-01 10:22:01 -050071{
72 ASSERT(mRenderer != nullptr);
Geoff Lang748f74e2014-12-01 11:25:34 -050073
74 std::fill(mColorBuffers.begin(), mColorBuffers.end(), nullptr);
Geoff Langb04dc822014-12-01 12:02:02 -050075
76 ASSERT(mDrawBuffers.size() > 0);
77 mDrawBuffers[0] = GL_COLOR_ATTACHMENT0;
78 std::fill(mDrawBuffers.begin() + 1, mDrawBuffers.end(), GL_NONE);
Geoff Langda88add2014-12-01 10:22:01 -050079}
80
81FramebufferD3D::~FramebufferD3D()
82{
83}
84
Geoff Lang9dd95802014-12-01 11:12:59 -050085void FramebufferD3D::setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment)
86{
Geoff Lang748f74e2014-12-01 11:25:34 -050087 ASSERT(index < mColorBuffers.size());
88 mColorBuffers[index] = attachment;
Geoff Lang9dd95802014-12-01 11:12:59 -050089}
90
91void FramebufferD3D::setDepthttachment(const gl::FramebufferAttachment *attachment)
92{
Geoff Langb04dc822014-12-01 12:02:02 -050093 mDepthbuffer = attachment;
Geoff Lang9dd95802014-12-01 11:12:59 -050094}
95
96void FramebufferD3D::setStencilAttachment(const gl::FramebufferAttachment *attachment)
97{
Geoff Langb04dc822014-12-01 12:02:02 -050098 mStencilbuffer = attachment;
Geoff Lang9dd95802014-12-01 11:12:59 -050099}
100
101void FramebufferD3D::setDepthStencilAttachment(const gl::FramebufferAttachment *attachment)
102{
Geoff Langb04dc822014-12-01 12:02:02 -0500103 mDepthbuffer = attachment;
104 mStencilbuffer = attachment;
Geoff Lang9dd95802014-12-01 11:12:59 -0500105}
106
107void FramebufferD3D::setDrawBuffers(size_t count, const GLenum *buffers)
108{
Geoff Langb04dc822014-12-01 12:02:02 -0500109 std::copy_n(buffers, count, mDrawBuffers.begin());
110 std::fill(mDrawBuffers.begin() + count, mDrawBuffers.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500111}
112
113void FramebufferD3D::setReadBuffer(GLenum buffer)
114{
Geoff Langbce529e2014-12-01 12:48:41 -0500115 mReadBuffer = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500116}
117
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500118gl::Error FramebufferD3D::invalidate(size_t, const GLenum *)
119{
120 // No-op in D3D
121 return gl::Error(GL_NO_ERROR);
122}
123
124gl::Error FramebufferD3D::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
125{
126 // No-op in D3D
127 return gl::Error(GL_NO_ERROR);
128}
129
Geoff Langb04dc822014-12-01 12:02:02 -0500130gl::Error FramebufferD3D::clear(const gl::State &state, GLbitfield mask)
131{
132 gl::ClearParameters clearParams = state.getClearParameters(mask);
133 return clear(state, clearParams);
134}
135
136gl::Error FramebufferD3D::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
137{
138 // glClearBufferfv can be called to clear the color buffer or depth buffer
139 gl::ClearParameters clearParams = state.getClearParameters(0);
140
141 if (buffer == GL_COLOR)
142 {
143 for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
144 {
145 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
146 }
147 clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]);
148 clearParams.colorClearType = GL_FLOAT;
149 }
150
151 if (buffer == GL_DEPTH)
152 {
153 clearParams.clearDepth = true;
154 clearParams.depthClearValue = values[0];
155 }
156
157 return clear(state, clearParams);
158}
159
160gl::Error FramebufferD3D::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
161{
162 // glClearBufferuiv can only be called to clear a color buffer
163 gl::ClearParameters clearParams = state.getClearParameters(0);
164 for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
165 {
166 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
167 }
168 clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]);
169 clearParams.colorClearType = GL_UNSIGNED_INT;
170
171 return clear(state, clearParams);
172}
173
174gl::Error FramebufferD3D::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
175{
176 // glClearBufferiv can be called to clear the color buffer or stencil buffer
177 gl::ClearParameters clearParams = state.getClearParameters(0);
178
179 if (buffer == GL_COLOR)
180 {
181 for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
182 {
183 clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
184 }
185 clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]);
186 clearParams.colorClearType = GL_INT;
187 }
188
189 if (buffer == GL_STENCIL)
190 {
191 clearParams.clearStencil = true;
192 clearParams.stencilClearValue = values[1];
193 }
194
195 return clear(state, clearParams);
196}
197
198gl::Error FramebufferD3D::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
199{
200 // glClearBufferfi can only be called to clear a depth stencil buffer
201 gl::ClearParameters clearParams = state.getClearParameters(0);
202 clearParams.clearDepth = true;
203 clearParams.depthClearValue = depth;
204 clearParams.clearStencil = true;
205 clearParams.stencilClearValue = stencil;
206
207 return clear(state, clearParams);
208}
209
Jamie Madillb885e572015-02-03 16:16:04 -0500210const gl::FramebufferAttachment *FramebufferD3D::getReadAttachment() const
211{
212 ASSERT(mReadBuffer == GL_BACK || (mReadBuffer >= GL_COLOR_ATTACHMENT0 && mReadBuffer <= GL_COLOR_ATTACHMENT15));
213 size_t readIndex = (mReadBuffer == GL_BACK ? 0 : static_cast<size_t>(mReadBuffer - GL_COLOR_ATTACHMENT0));
214 ASSERT(readIndex < mColorBuffers.size());
215 return mColorBuffers[readIndex];
216}
217
Geoff Langbce529e2014-12-01 12:48:41 -0500218GLenum FramebufferD3D::getImplementationColorReadFormat() const
219{
Jamie Madillb885e572015-02-03 16:16:04 -0500220 const gl::FramebufferAttachment *readAttachment = getReadAttachment();
Geoff Langbce529e2014-12-01 12:48:41 -0500221
Jamie Madillb885e572015-02-03 16:16:04 -0500222 if (readAttachment == nullptr)
Geoff Langbce529e2014-12-01 12:48:41 -0500223 {
224 return GL_NONE;
225 }
226
Geoff Langc2e75af2015-01-05 14:26:24 -0500227 RenderTargetD3D *attachmentRenderTarget = NULL;
Jamie Madillb885e572015-02-03 16:16:04 -0500228 gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget);
Geoff Langd8a22582014-12-17 15:28:23 -0500229 if (error.isError())
230 {
231 return GL_NONE;
232 }
Geoff Langbce529e2014-12-01 12:48:41 -0500233
Geoff Langd8a22582014-12-17 15:28:23 -0500234 GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget);
235 const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat);
236
237 return implementationFormatInfo.format;
Geoff Langbce529e2014-12-01 12:48:41 -0500238}
239
240GLenum FramebufferD3D::getImplementationColorReadType() const
241{
Jamie Madillb885e572015-02-03 16:16:04 -0500242 const gl::FramebufferAttachment *readAttachment = getReadAttachment();
Geoff Langbce529e2014-12-01 12:48:41 -0500243
Jamie Madillb885e572015-02-03 16:16:04 -0500244 if (readAttachment == nullptr)
Geoff Langbce529e2014-12-01 12:48:41 -0500245 {
246 return GL_NONE;
247 }
248
Geoff Langc2e75af2015-01-05 14:26:24 -0500249 RenderTargetD3D *attachmentRenderTarget = NULL;
Jamie Madillb885e572015-02-03 16:16:04 -0500250 gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget);
Geoff Langd8a22582014-12-17 15:28:23 -0500251 if (error.isError())
252 {
253 return GL_NONE;
254 }
Geoff Langbce529e2014-12-01 12:48:41 -0500255
Geoff Langd8a22582014-12-17 15:28:23 -0500256 GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget);
257 const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat);
258
259 return implementationFormatInfo.type;
Geoff Langbce529e2014-12-01 12:48:41 -0500260}
261
262gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
263{
264 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type);
265 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Minmin Gongb8aee3b2015-01-27 14:42:36 -0800266 GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, area.width, state.getPackAlignment(), 0);
Geoff Langbce529e2014-12-01 12:48:41 -0500267
268 return readPixels(area, format, type, outputPitch, state.getPackState(), reinterpret_cast<uint8_t*>(pixels));
269}
270
Geoff Lang54bd5a42014-12-01 12:51:04 -0500271gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
272 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
273{
274 bool blitRenderTarget = false;
275 if ((mask & GL_COLOR_BUFFER_BIT) &&
276 sourceFramebuffer->getReadColorbuffer() != nullptr &&
277 std::any_of(mColorBuffers.begin(), mColorBuffers.end(), [](const gl::FramebufferAttachment* attachment){ return attachment != nullptr; }))
278 {
279 blitRenderTarget = true;
280 }
281
282 bool blitStencil = false;
283 if ((mask & GL_STENCIL_BUFFER_BIT) &&
284 sourceFramebuffer->getStencilbuffer() != nullptr &&
285 mStencilbuffer != nullptr)
286 {
287 blitStencil = true;
288 }
289
290 bool blitDepth = false;
291 if ((mask & GL_DEPTH_BUFFER_BIT) &&
292 sourceFramebuffer->getDepthbuffer() != nullptr &&
293 mDepthbuffer != nullptr)
294 {
295 blitDepth = true;
296 }
297
298 if (blitRenderTarget || blitDepth || blitStencil)
299 {
300 const gl::Rectangle *scissor = state.isScissorTestEnabled() ? &state.getScissor() : NULL;
301 gl::Error error = blit(sourceArea, destArea, scissor, blitRenderTarget, blitDepth, blitStencil,
302 filter, sourceFramebuffer);
303 if (error.isError())
304 {
305 return error;
306 }
307 }
308
309 return gl::Error(GL_NO_ERROR);
310}
311
Geoff Lang748f74e2014-12-01 11:25:34 -0500312GLenum FramebufferD3D::checkStatus() const
313{
314 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
315 for (size_t colorAttachment = 0; colorAttachment < mColorBuffers.size(); colorAttachment++)
316 {
317 const gl::FramebufferAttachment *attachment = mColorBuffers[colorAttachment];
318 if (attachment != nullptr)
319 {
320 for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++)
321 {
322 const gl::FramebufferAttachment *prevAttachment = mColorBuffers[prevColorAttachment];
323 if (prevAttachment != nullptr &&
324 (attachment->id() == prevAttachment->id() &&
325 attachment->type() == prevAttachment->type()))
326 {
327 return GL_FRAMEBUFFER_UNSUPPORTED;
328 }
329 }
330 }
331 }
332
333 return GL_FRAMEBUFFER_COMPLETE;
334}
335
Geoff Langc2e75af2015-01-05 14:26:24 -0500336gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT)
Geoff Langb5d8f232014-12-04 15:43:01 -0500337{
338 if (attachment->type() == GL_TEXTURE)
339 {
340 gl::Texture *texture = attachment->getTexture();
341 ASSERT(texture);
Jamie Madill9236b412015-02-02 16:51:52 -0500342 TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
Geoff Langb5d8f232014-12-04 15:43:01 -0500343 const gl::ImageIndex *index = attachment->getTextureImageIndex();
344 ASSERT(index);
345 return textureD3D->getRenderTarget(*index, outRT);
346 }
347 else if (attachment->type() == GL_RENDERBUFFER)
348 {
349 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
350 ASSERT(renderbuffer);
351 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
352 *outRT = renderbufferD3D->getRenderTarget();
353 return gl::Error(GL_NO_ERROR);
354 }
355 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
356 {
357 const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
358 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
359 ASSERT(defaultAttachmentD3D);
360
361 *outRT = defaultAttachmentD3D->getRenderTarget();
362 return gl::Error(GL_NO_ERROR);
363 }
364 else
365 {
366 UNREACHABLE();
367 return gl::Error(GL_INVALID_OPERATION);
368 }
369}
370
371// Note: RenderTarget serials should ideally be in the RenderTargets themselves.
372unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment)
373{
374 if (attachment->type() == GL_TEXTURE)
375 {
376 gl::Texture *texture = attachment->getTexture();
377 ASSERT(texture);
Jamie Madill9236b412015-02-02 16:51:52 -0500378 TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
Geoff Langb5d8f232014-12-04 15:43:01 -0500379 const gl::ImageIndex *index = attachment->getTextureImageIndex();
380 ASSERT(index);
381 return textureD3D->getRenderTargetSerial(*index);
382 }
383 else if (attachment->type() == GL_RENDERBUFFER)
384 {
385 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
386 ASSERT(renderbuffer);
387 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
388 return renderbufferD3D->getRenderTargetSerial();
389 }
390 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
391 {
392 const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
393 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
394 ASSERT(defaultAttachmentD3D);
395 return defaultAttachmentD3D->getRenderTarget()->getSerial();
396 }
397 else
398 {
399 UNREACHABLE();
400 return 0;
401 }
402}
403
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500404}