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