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