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 // Framebuffer9.cpp: Implements the Framebuffer9 class.
8 
9 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
10 
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Framebuffer.h"
13 #include "libANGLE/FramebufferAttachment.h"
14 #include "libANGLE/Texture.h"
15 #include "libANGLE/formatutils.h"
16 #include "libANGLE/renderer/ContextImpl.h"
17 #include "libANGLE/renderer/d3d/TextureD3D.h"
18 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
19 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
20 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
21 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
22 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
23 #include "libANGLE/renderer/renderer_utils.h"
24 
25 namespace rx
26 {
27 
Framebuffer9(const gl::FramebufferState & data,Renderer9 * renderer)28 Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer)
29     : FramebufferD3D(data, renderer), mRenderer(renderer)
30 {
31     ASSERT(mRenderer != nullptr);
32 }
33 
~Framebuffer9()34 Framebuffer9::~Framebuffer9()
35 {
36 }
37 
discard(const gl::Context * context,size_t,const GLenum *)38 gl::Error Framebuffer9::discard(const gl::Context *context, size_t, const GLenum *)
39 {
40     // Extension not implemented in D3D9 renderer
41     UNREACHABLE();
42     return gl::NoError();
43 }
44 
invalidate(const gl::Context * context,size_t,const GLenum *)45 gl::Error Framebuffer9::invalidate(const gl::Context *context, size_t, const GLenum *)
46 {
47     // Shouldn't ever reach here in D3D9
48     UNREACHABLE();
49     return gl::NoError();
50 }
51 
invalidateSub(const gl::Context * context,size_t,const GLenum *,const gl::Rectangle &)52 gl::Error Framebuffer9::invalidateSub(const gl::Context *context,
53                                       size_t,
54                                       const GLenum *,
55                                       const gl::Rectangle &)
56 {
57     // Shouldn't ever reach here in D3D9
58     UNREACHABLE();
59     return gl::NoError();
60 }
61 
clearImpl(const gl::Context * context,const ClearParameters & clearParams)62 gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParameters &clearParams)
63 {
64     const gl::FramebufferAttachment *colorAttachment        = mState.getColorAttachment(0);
65     const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment();
66 
67     ANGLE_TRY(mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment));
68 
69     const gl::State &glState = context->getGLState();
70     float nearZ              = glState.getNearPlane();
71     float farZ = glState.getFarPlane();
72     mRenderer->setViewport(glState.getViewport(), nearZ, farZ, GL_TRIANGLES,
73                            glState.getRasterizerState().frontFace, true);
74 
75     mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
76 
77     return mRenderer->clear(context, clearParams, colorAttachment, depthStencilAttachment);
78 }
79 
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,uint8_t * pixels)80 gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context,
81                                        const gl::Rectangle &area,
82                                        GLenum format,
83                                        GLenum type,
84                                        size_t outputPitch,
85                                        const gl::PixelPackState &pack,
86                                        uint8_t *pixels)
87 {
88     const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0);
89     ASSERT(colorbuffer);
90 
91     RenderTarget9 *renderTarget = nullptr;
92     ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget));
93     ASSERT(renderTarget);
94 
95     IDirect3DSurface9 *surface = renderTarget->getSurface();
96     ASSERT(surface);
97 
98     D3DSURFACE_DESC desc;
99     surface->GetDesc(&desc);
100 
101     if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
102     {
103         UNIMPLEMENTED();   // FIXME: Requires resolve using StretchRect into non-multisampled render target
104         SafeRelease(surface);
105         return gl::OutOfMemory()
106                << "ReadPixels is unimplemented for multisampled framebuffer attachments.";
107     }
108 
109     IDirect3DDevice9 *device = mRenderer->getDevice();
110     ASSERT(device);
111 
112     HRESULT result;
113     IDirect3DSurface9 *systemSurface = nullptr;
114     bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
115                           area.x == 0 && area.y == 0 &&
116                           static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
117                           desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
118     if (directToPixels)
119     {
120         // Use the pixels ptr as a shared handle to write directly into client's memory
121         result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
122                                                      D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
123         if (FAILED(result))
124         {
125             // Try again without the shared handle
126             directToPixels = false;
127         }
128     }
129 
130     if (!directToPixels)
131     {
132         result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
133                                                      D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
134         if (FAILED(result))
135         {
136             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
137             SafeRelease(surface);
138             return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels.";
139         }
140     }
141 
142     result = device->GetRenderTargetData(surface, systemSurface);
143     SafeRelease(surface);
144 
145     if (FAILED(result))
146     {
147         SafeRelease(systemSurface);
148 
149         // It turns out that D3D will sometimes produce more error
150         // codes than those documented.
151         if (d3d9::isDeviceLostError(result))
152         {
153             mRenderer->notifyDeviceLost();
154         }
155         else
156         {
157             UNREACHABLE();
158         }
159 
160         return gl::OutOfMemory() << "Failed to read internal render target data.";
161     }
162 
163     if (directToPixels)
164     {
165         SafeRelease(systemSurface);
166         return gl::NoError();
167     }
168 
169     RECT rect;
170     rect.left = gl::clamp(area.x, 0L, static_cast<LONG>(desc.Width));
171     rect.top = gl::clamp(area.y, 0L, static_cast<LONG>(desc.Height));
172     rect.right = gl::clamp(area.x + area.width, 0L, static_cast<LONG>(desc.Width));
173     rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast<LONG>(desc.Height));
174 
175     D3DLOCKED_RECT lock;
176     result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
177 
178     if (FAILED(result))
179     {
180         UNREACHABLE();
181         SafeRelease(systemSurface);
182 
183         return gl::OutOfMemory() << "Failed to lock internal render target.";
184     }
185 
186     uint8_t *source = reinterpret_cast<uint8_t *>(lock.pBits);
187     int inputPitch  = lock.Pitch;
188 
189     const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
190     gl::FormatType formatType(format, type);
191 
192     PackPixelsParams packParams;
193     packParams.area.x      = rect.left;
194     packParams.area.y      = rect.top;
195     packParams.area.width  = rect.right - rect.left;
196     packParams.area.height = rect.bottom - rect.top;
197     packParams.format      = format;
198     packParams.type        = type;
199     packParams.outputPitch = static_cast<GLuint>(outputPitch);
200     packParams.pack        = pack;
201 
202     PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels);
203 
204     systemSurface->UnlockRect();
205     SafeRelease(systemSurface);
206 
207     return gl::NoError();
208 }
209 
blitImpl(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,const gl::Rectangle * scissor,bool blitRenderTarget,bool blitDepth,bool blitStencil,GLenum filter,const gl::Framebuffer * sourceFramebuffer)210 gl::Error Framebuffer9::blitImpl(const gl::Context *context,
211                                  const gl::Rectangle &sourceArea,
212                                  const gl::Rectangle &destArea,
213                                  const gl::Rectangle *scissor,
214                                  bool blitRenderTarget,
215                                  bool blitDepth,
216                                  bool blitStencil,
217                                  GLenum filter,
218                                  const gl::Framebuffer *sourceFramebuffer)
219 {
220     ASSERT(filter == GL_NEAREST);
221 
222     IDirect3DDevice9 *device = mRenderer->getDevice();
223     ASSERT(device);
224 
225     mRenderer->endScene();
226 
227     if (blitRenderTarget)
228     {
229         const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0);
230         ASSERT(readBuffer);
231 
232         RenderTarget9 *readRenderTarget = nullptr;
233         gl::Error error                 = readBuffer->getRenderTarget(context, &readRenderTarget);
234         if (error.isError())
235         {
236             return error;
237         }
238         ASSERT(readRenderTarget);
239 
240         const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0);
241         ASSERT(drawBuffer);
242 
243         RenderTarget9 *drawRenderTarget = nullptr;
244         error                           = drawBuffer->getRenderTarget(context, &drawRenderTarget);
245         if (error.isError())
246         {
247             return error;
248         }
249         ASSERT(drawRenderTarget);
250 
251         // The getSurface calls do an AddRef so save them until after no errors are possible
252         IDirect3DSurface9* readSurface = readRenderTarget->getSurface();
253         ASSERT(readSurface);
254 
255         IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface();
256         ASSERT(drawSurface);
257 
258         gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
259         gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
260 
261         RECT srcRect;
262         srcRect.left = sourceArea.x;
263         srcRect.right = sourceArea.x + sourceArea.width;
264         srcRect.top = sourceArea.y;
265         srcRect.bottom = sourceArea.y + sourceArea.height;
266 
267         RECT dstRect;
268         dstRect.left = destArea.x;
269         dstRect.right = destArea.x + destArea.width;
270         dstRect.top = destArea.y;
271         dstRect.bottom = destArea.y + destArea.height;
272 
273         // Clip the rectangles to the scissor rectangle
274         if (scissor)
275         {
276             if (dstRect.left < scissor->x)
277             {
278                 srcRect.left += (scissor->x - dstRect.left);
279                 dstRect.left = scissor->x;
280             }
281             if (dstRect.top < scissor->y)
282             {
283                 srcRect.top += (scissor->y - dstRect.top);
284                 dstRect.top = scissor->y;
285             }
286             if (dstRect.right > scissor->x + scissor->width)
287             {
288                 srcRect.right -= (dstRect.right - (scissor->x + scissor->width));
289                 dstRect.right = scissor->x + scissor->width;
290             }
291             if (dstRect.bottom > scissor->y + scissor->height)
292             {
293                 srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height));
294                 dstRect.bottom = scissor->y + scissor->height;
295             }
296         }
297 
298         // Clip the rectangles to the destination size
299         if (dstRect.left < 0)
300         {
301             srcRect.left += -dstRect.left;
302             dstRect.left = 0;
303         }
304         if (dstRect.right > dstSize.width)
305         {
306             srcRect.right -= (dstRect.right - dstSize.width);
307             dstRect.right = dstSize.width;
308         }
309         if (dstRect.top < 0)
310         {
311             srcRect.top += -dstRect.top;
312             dstRect.top = 0;
313         }
314         if (dstRect.bottom > dstSize.height)
315         {
316             srcRect.bottom -= (dstRect.bottom - dstSize.height);
317             dstRect.bottom = dstSize.height;
318         }
319 
320         // Clip the rectangles to the source size
321         if (srcRect.left < 0)
322         {
323             dstRect.left += -srcRect.left;
324             srcRect.left = 0;
325         }
326         if (srcRect.right > srcSize.width)
327         {
328             dstRect.right -= (srcRect.right - srcSize.width);
329             srcRect.right = srcSize.width;
330         }
331         if (srcRect.top < 0)
332         {
333             dstRect.top += -srcRect.top;
334             srcRect.top = 0;
335         }
336         if (srcRect.bottom > srcSize.height)
337         {
338             dstRect.bottom -= (srcRect.bottom - srcSize.height);
339             srcRect.bottom = srcSize.height;
340         }
341 
342         HRESULT result = device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
343 
344         SafeRelease(readSurface);
345         SafeRelease(drawSurface);
346 
347         if (FAILED(result))
348         {
349             return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result);
350         }
351     }
352 
353     if (blitDepth || blitStencil)
354     {
355         const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
356         ASSERT(readBuffer);
357 
358         RenderTarget9 *readDepthStencil = nullptr;
359         gl::Error error                 = readBuffer->getRenderTarget(context, &readDepthStencil);
360         if (error.isError())
361         {
362             return error;
363         }
364         ASSERT(readDepthStencil);
365 
366         const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
367         ASSERT(drawBuffer);
368 
369         RenderTarget9 *drawDepthStencil = nullptr;
370         error                           = drawBuffer->getRenderTarget(context, &drawDepthStencil);
371         if (error.isError())
372         {
373             return error;
374         }
375         ASSERT(drawDepthStencil);
376 
377         // The getSurface calls do an AddRef so save them until after no errors are possible
378         IDirect3DSurface9* readSurface = readDepthStencil->getSurface();
379         ASSERT(readDepthStencil);
380 
381         IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface();
382         ASSERT(drawDepthStencil);
383 
384         HRESULT result = device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE);
385 
386         SafeRelease(readSurface);
387         SafeRelease(drawSurface);
388 
389         if (FAILED(result))
390         {
391             return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result);
392         }
393     }
394 
395     return gl::NoError();
396 }
397 
getRenderTargetImplementationFormat(RenderTargetD3D * renderTarget) const398 GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
399 {
400     RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget);
401     const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat());
402     return d3dFormatInfo.info().glInternalFormat;
403 }
404 
getSamplePosition(size_t index,GLfloat * xy) const405 gl::Error Framebuffer9::getSamplePosition(size_t index, GLfloat *xy) const
406 {
407     UNREACHABLE();
408     return gl::InternalError() << "getSamplePosition is unsupported to d3d9.";
409 }
410 
411 }  // namespace rx
412