1 //
2 // Copyright 2002 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 // Blit9.cpp: Surface copy utility class.
8
9 #include "libANGLE/renderer/d3d/d3d9/Blit9.h"
10
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Framebuffer.h"
13 #include "libANGLE/FramebufferAttachment.h"
14 #include "libANGLE/angletypes.h"
15 #include "libANGLE/renderer/d3d/TextureD3D.h"
16 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
17 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
18 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
19 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
20 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
21
22 namespace
23 {
24 // Precompiled shaders
25 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h"
26 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
27 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h"
28 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h"
29 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
30 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h"
31 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
32 #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
33
34 const BYTE *const g_shaderCode[] = {
35 g_vs20_standardvs,
36 g_ps20_passthroughps,
37 g_ps20_luminanceps,
38 g_ps20_luminancepremultps,
39 g_ps20_luminanceunmultps,
40 g_ps20_componentmaskps,
41 g_ps20_componentmaskpremultps,
42 g_ps20_componentmaskunmultps,
43 };
44
45 const size_t g_shaderSize[] = {
46 sizeof(g_vs20_standardvs),
47 sizeof(g_ps20_passthroughps),
48 sizeof(g_ps20_luminanceps),
49 sizeof(g_ps20_luminancepremultps),
50 sizeof(g_ps20_luminanceunmultps),
51 sizeof(g_ps20_componentmaskps),
52 sizeof(g_ps20_componentmaskpremultps),
53 sizeof(g_ps20_componentmaskunmultps),
54 };
55 } // namespace
56
57 namespace rx
58 {
59
Blit9(Renderer9 * renderer)60 Blit9::Blit9(Renderer9 *renderer)
61 : mRenderer(renderer),
62 mGeometryLoaded(false),
63 mQuadVertexBuffer(nullptr),
64 mQuadVertexDeclaration(nullptr),
65 mSavedStateBlock(nullptr),
66 mSavedRenderTarget(nullptr),
67 mSavedDepthStencil(nullptr)
68 {
69 memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
70 }
71
~Blit9()72 Blit9::~Blit9()
73 {
74 SafeRelease(mSavedStateBlock);
75 SafeRelease(mQuadVertexBuffer);
76 SafeRelease(mQuadVertexDeclaration);
77
78 for (int i = 0; i < SHADER_COUNT; i++)
79 {
80 SafeRelease(mCompiledShaders[i]);
81 }
82 }
83
initialize(Context9 * context9)84 angle::Result Blit9::initialize(Context9 *context9)
85 {
86 if (mGeometryLoaded)
87 {
88 return angle::Result::Continue;
89 }
90
91 static const float quad[] = {-1, -1, -1, 1, 1, -1, 1, 1};
92
93 IDirect3DDevice9 *device = mRenderer->getDevice();
94
95 HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0,
96 D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr);
97
98 ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader");
99
100 void *lockPtr = nullptr;
101 result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
102
103 ANGLE_TRY_HR(context9, result, "Failed to lock internal blit vertex shader");
104 ASSERT(lockPtr);
105
106 memcpy(lockPtr, quad, sizeof(quad));
107 mQuadVertexBuffer->Unlock();
108
109 static const D3DVERTEXELEMENT9 elements[] = {
110 {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, D3DDECL_END()};
111
112 result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
113 ANGLE_TRY_HR(context9, result, "Failed to create internal blit vertex shader declaration");
114
115 mGeometryLoaded = true;
116 return angle::Result::Continue;
117 }
118
119 template <class D3DShaderType>
setShader(Context9 * context9,ShaderId source,const char * profile,angle::Result (Renderer9::* createShader)(d3d::Context *,const DWORD *,size_t length,D3DShaderType ** outShader),HRESULT (WINAPI IDirect3DDevice9::* setShader)(D3DShaderType *))120 angle::Result Blit9::setShader(Context9 *context9,
121 ShaderId source,
122 const char *profile,
123 angle::Result (Renderer9::*createShader)(d3d::Context *,
124 const DWORD *,
125 size_t length,
126 D3DShaderType **outShader),
127 HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType *))
128 {
129 IDirect3DDevice9 *device = mRenderer->getDevice();
130
131 D3DShaderType *shader = nullptr;
132
133 if (mCompiledShaders[source] != nullptr)
134 {
135 shader = static_cast<D3DShaderType *>(mCompiledShaders[source]);
136 }
137 else
138 {
139 const BYTE *shaderCode = g_shaderCode[source];
140 size_t shaderSize = g_shaderSize[source];
141 ANGLE_TRY((mRenderer->*createShader)(context9, reinterpret_cast<const DWORD *>(shaderCode),
142 shaderSize, &shader));
143 mCompiledShaders[source] = shader;
144 }
145
146 HRESULT hr = (device->*setShader)(shader);
147 ANGLE_TRY_HR(context9, hr, "Failed to set shader for blit operation");
148 return angle::Result::Continue;
149 }
150
setVertexShader(Context9 * context9,ShaderId shader)151 angle::Result Blit9::setVertexShader(Context9 *context9, ShaderId shader)
152 {
153 return setShader<IDirect3DVertexShader9>(context9, shader, "vs_2_0",
154 &Renderer9::createVertexShader,
155 &IDirect3DDevice9::SetVertexShader);
156 }
157
setPixelShader(Context9 * context9,ShaderId shader)158 angle::Result Blit9::setPixelShader(Context9 *context9, ShaderId shader)
159 {
160 return setShader<IDirect3DPixelShader9>(context9, shader, "ps_2_0",
161 &Renderer9::createPixelShader,
162 &IDirect3DDevice9::SetPixelShader);
163 }
164
getSurfaceRect(IDirect3DSurface9 * surface) const165 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
166 {
167 D3DSURFACE_DESC desc;
168 surface->GetDesc(&desc);
169
170 RECT rect;
171 rect.left = 0;
172 rect.top = 0;
173 rect.right = desc.Width;
174 rect.bottom = desc.Height;
175
176 return rect;
177 }
178
getSurfaceSize(IDirect3DSurface9 * surface) const179 gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const
180 {
181 D3DSURFACE_DESC desc;
182 surface->GetDesc(&desc);
183
184 return gl::Extents(desc.Width, desc.Height, 1);
185 }
186
boxFilter(Context9 * context9,IDirect3DSurface9 * source,IDirect3DSurface9 * dest)187 angle::Result Blit9::boxFilter(Context9 *context9,
188 IDirect3DSurface9 *source,
189 IDirect3DSurface9 *dest)
190 {
191 ANGLE_TRY(initialize(context9));
192
193 angle::ComPtr<IDirect3DBaseTexture9> texture = nullptr;
194 ANGLE_TRY(copySurfaceToTexture(context9, source, getSurfaceRect(source), &texture));
195
196 IDirect3DDevice9 *device = mRenderer->getDevice();
197
198 saveState();
199
200 device->SetTexture(0, texture.Get());
201 device->SetRenderTarget(0, dest);
202
203 ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD));
204 ANGLE_TRY(setPixelShader(context9, SHADER_PS_PASSTHROUGH));
205
206 setCommonBlitState();
207 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
208 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
209
210 setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source),
211 getSurfaceRect(dest), false);
212
213 render();
214
215 restoreState();
216
217 return angle::Result::Continue;
218 }
219
copy2D(const gl::Context * context,const gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)220 angle::Result Blit9::copy2D(const gl::Context *context,
221 const gl::Framebuffer *framebuffer,
222 const RECT &sourceRect,
223 GLenum destFormat,
224 const gl::Offset &destOffset,
225 TextureStorage *storage,
226 GLint level)
227 {
228 Context9 *context9 = GetImplAs<Context9>(context);
229
230 ANGLE_TRY(initialize(context9));
231
232 const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0);
233 ASSERT(colorbuffer);
234
235 RenderTarget9 *renderTarget9 = nullptr;
236 ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget9));
237 ASSERT(renderTarget9);
238
239 angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface();
240 ASSERT(source);
241
242 angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
243 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
244 ANGLE_TRY(
245 storage9->getSurfaceLevel(context, gl::TextureTarget::_2D, level, true, &destSurface));
246 ASSERT(destSurface);
247
248 ANGLE_TRY(copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset,
249 destSurface.Get(), false, false, false));
250 return angle::Result::Continue;
251 }
252
copyCube(const gl::Context * context,const gl::Framebuffer * framebuffer,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,gl::TextureTarget target,GLint level)253 angle::Result Blit9::copyCube(const gl::Context *context,
254 const gl::Framebuffer *framebuffer,
255 const RECT &sourceRect,
256 GLenum destFormat,
257 const gl::Offset &destOffset,
258 TextureStorage *storage,
259 gl::TextureTarget target,
260 GLint level)
261 {
262 Context9 *context9 = GetImplAs<Context9>(context);
263
264 ANGLE_TRY(initialize(context9));
265
266 const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorAttachment(0);
267 ASSERT(colorbuffer);
268
269 RenderTarget9 *renderTarget9 = nullptr;
270 ANGLE_TRY(colorbuffer->getRenderTarget(context, 0, &renderTarget9));
271 ASSERT(renderTarget9);
272
273 angle::ComPtr<IDirect3DSurface9> source = renderTarget9->getSurface();
274 ASSERT(source);
275
276 angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
277 TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
278 ANGLE_TRY(storage9->getSurfaceLevel(context, target, level, true, &destSurface));
279 ASSERT(destSurface);
280
281 return copy(context9, source.Get(), nullptr, sourceRect, destFormat, destOffset,
282 destSurface.Get(), false, false, false);
283 }
284
copyTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,gl::TextureTarget destTarget,GLint destLevel,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)285 angle::Result Blit9::copyTexture(const gl::Context *context,
286 const gl::Texture *source,
287 GLint sourceLevel,
288 const RECT &sourceRect,
289 GLenum destFormat,
290 const gl::Offset &destOffset,
291 TextureStorage *storage,
292 gl::TextureTarget destTarget,
293 GLint destLevel,
294 bool flipY,
295 bool premultiplyAlpha,
296 bool unmultiplyAlpha)
297 {
298 Context9 *context9 = GetImplAs<Context9>(context);
299 ANGLE_TRY(initialize(context9));
300
301 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
302
303 TextureStorage *sourceStorage = nullptr;
304 ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage));
305
306 TextureStorage9_2D *sourceStorage9 = GetAs<TextureStorage9_2D>(sourceStorage);
307 ASSERT(sourceStorage9);
308
309 TextureStorage9 *destStorage9 = GetAs<TextureStorage9>(storage);
310 ASSERT(destStorage9);
311
312 ASSERT(sourceLevel == 0);
313 IDirect3DBaseTexture9 *sourceTexture = nullptr;
314 ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture));
315
316 angle::ComPtr<IDirect3DSurface9> sourceSurface = nullptr;
317 ANGLE_TRY(sourceStorage9->getSurfaceLevel(context, gl::TextureTarget::_2D, sourceLevel, true,
318 &sourceSurface));
319
320 angle::ComPtr<IDirect3DSurface9> destSurface = nullptr;
321 ANGLE_TRY(destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface));
322
323 return copy(context9, sourceSurface.Get(), sourceTexture, sourceRect, destFormat, destOffset,
324 destSurface.Get(), flipY, premultiplyAlpha, unmultiplyAlpha);
325 }
326
copy(Context9 * context9,IDirect3DSurface9 * source,IDirect3DBaseTexture9 * sourceTexture,const RECT & sourceRect,GLenum destFormat,const gl::Offset & destOffset,IDirect3DSurface9 * dest,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)327 angle::Result Blit9::copy(Context9 *context9,
328 IDirect3DSurface9 *source,
329 IDirect3DBaseTexture9 *sourceTexture,
330 const RECT &sourceRect,
331 GLenum destFormat,
332 const gl::Offset &destOffset,
333 IDirect3DSurface9 *dest,
334 bool flipY,
335 bool premultiplyAlpha,
336 bool unmultiplyAlpha)
337 {
338 ASSERT(source != nullptr && dest != nullptr);
339
340 IDirect3DDevice9 *device = mRenderer->getDevice();
341
342 D3DSURFACE_DESC sourceDesc;
343 D3DSURFACE_DESC destDesc;
344 source->GetDesc(&sourceDesc);
345 dest->GetDesc(&destDesc);
346
347 // Check if it's possible to use StetchRect
348 if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) &&
349 d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY &&
350 premultiplyAlpha == unmultiplyAlpha)
351 {
352 RECT destRect = {destOffset.x, destOffset.y,
353 destOffset.x + (sourceRect.right - sourceRect.left),
354 destOffset.y + (sourceRect.bottom - sourceRect.top)};
355 HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
356 ANGLE_TRY_HR(context9, result, "StretchRect failed to blit between textures");
357 return angle::Result::Continue;
358 }
359
360 angle::ComPtr<IDirect3DBaseTexture9> texture = sourceTexture;
361 RECT adjustedSourceRect = sourceRect;
362 gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1);
363
364 if (texture == nullptr)
365 {
366 ANGLE_TRY(copySurfaceToTexture(context9, source, sourceRect, &texture));
367
368 // copySurfaceToTexture only copies in the sourceRect area of the source surface.
369 // Adjust sourceRect so that it is now covering the entire source texture
370 adjustedSourceRect.left = 0;
371 adjustedSourceRect.right = sourceRect.right - sourceRect.left;
372 adjustedSourceRect.top = 0;
373 adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top;
374
375 sourceSize.width = sourceRect.right - sourceRect.left;
376 sourceSize.height = sourceRect.bottom - sourceRect.top;
377 }
378
379 ANGLE_TRY(formatConvert(context9, texture.Get(), adjustedSourceRect, sourceSize, destFormat,
380 destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha));
381 return angle::Result::Continue;
382 }
383
formatConvert(Context9 * context9,IDirect3DBaseTexture9 * source,const RECT & sourceRect,const gl::Extents & sourceSize,GLenum destFormat,const gl::Offset & destOffset,IDirect3DSurface9 * dest,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)384 angle::Result Blit9::formatConvert(Context9 *context9,
385 IDirect3DBaseTexture9 *source,
386 const RECT &sourceRect,
387 const gl::Extents &sourceSize,
388 GLenum destFormat,
389 const gl::Offset &destOffset,
390 IDirect3DSurface9 *dest,
391 bool flipY,
392 bool premultiplyAlpha,
393 bool unmultiplyAlpha)
394 {
395 ANGLE_TRY(initialize(context9));
396
397 IDirect3DDevice9 *device = mRenderer->getDevice();
398
399 saveState();
400
401 device->SetTexture(0, source);
402 device->SetRenderTarget(0, dest);
403
404 RECT destRect;
405 destRect.left = destOffset.x;
406 destRect.right = destOffset.x + (sourceRect.right - sourceRect.left);
407 destRect.top = destOffset.y;
408 destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top);
409
410 setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY);
411
412 setCommonBlitState();
413
414 angle::Result result =
415 setFormatConvertShaders(context9, destFormat, flipY, premultiplyAlpha, unmultiplyAlpha);
416 if (result == angle::Result::Continue)
417 {
418 render();
419 }
420
421 restoreState();
422
423 return result;
424 }
425
setFormatConvertShaders(Context9 * context9,GLenum destFormat,bool flipY,bool premultiplyAlpha,bool unmultiplyAlpha)426 angle::Result Blit9::setFormatConvertShaders(Context9 *context9,
427 GLenum destFormat,
428 bool flipY,
429 bool premultiplyAlpha,
430 bool unmultiplyAlpha)
431 {
432 ANGLE_TRY(setVertexShader(context9, SHADER_VS_STANDARD));
433
434 switch (destFormat)
435 {
436 case GL_RGBA:
437 case GL_BGRA_EXT:
438 case GL_RGB:
439 case GL_RG_EXT:
440 case GL_RED_EXT:
441 case GL_ALPHA:
442 if (premultiplyAlpha == unmultiplyAlpha)
443 {
444 ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK));
445 }
446 else if (premultiplyAlpha)
447 {
448 ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA));
449 }
450 else
451 {
452 ASSERT(unmultiplyAlpha);
453 ANGLE_TRY(setPixelShader(context9, SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA));
454 }
455 break;
456
457 case GL_LUMINANCE:
458 case GL_LUMINANCE_ALPHA:
459 if (premultiplyAlpha == unmultiplyAlpha)
460 {
461 ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE));
462 }
463 else if (premultiplyAlpha)
464 {
465 ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA));
466 }
467 else
468 {
469 ASSERT(unmultiplyAlpha);
470 ANGLE_TRY(setPixelShader(context9, SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA));
471 }
472 break;
473
474 default:
475 UNREACHABLE();
476 }
477
478 enum
479 {
480 X = 0,
481 Y = 1,
482 Z = 2,
483 W = 3
484 };
485
486 // The meaning of this constant depends on the shader that was selected.
487 // See the shader assembly code above for details.
488 // Allocate one array for both registers and split it into two float4's.
489 float psConst[8] = {0};
490 float *multConst = &psConst[0];
491 float *addConst = &psConst[4];
492
493 switch (destFormat)
494 {
495 case GL_RGBA:
496 case GL_BGRA_EXT:
497 multConst[X] = 1;
498 multConst[Y] = 1;
499 multConst[Z] = 1;
500 multConst[W] = 1;
501 addConst[X] = 0;
502 addConst[Y] = 0;
503 addConst[Z] = 0;
504 addConst[W] = 0;
505 break;
506
507 case GL_RGB:
508 multConst[X] = 1;
509 multConst[Y] = 1;
510 multConst[Z] = 1;
511 multConst[W] = 0;
512 addConst[X] = 0;
513 addConst[Y] = 0;
514 addConst[Z] = 0;
515 addConst[W] = 1;
516 break;
517
518 case GL_RG_EXT:
519 multConst[X] = 1;
520 multConst[Y] = 1;
521 multConst[Z] = 0;
522 multConst[W] = 0;
523 addConst[X] = 0;
524 addConst[Y] = 0;
525 addConst[Z] = 0;
526 addConst[W] = 1;
527 break;
528
529 case GL_RED_EXT:
530 multConst[X] = 1;
531 multConst[Y] = 0;
532 multConst[Z] = 0;
533 multConst[W] = 0;
534 addConst[X] = 0;
535 addConst[Y] = 0;
536 addConst[Z] = 0;
537 addConst[W] = 1;
538 break;
539
540 case GL_ALPHA:
541 multConst[X] = 0;
542 multConst[Y] = 0;
543 multConst[Z] = 0;
544 multConst[W] = 1;
545 addConst[X] = 0;
546 addConst[Y] = 0;
547 addConst[Z] = 0;
548 addConst[W] = 0;
549 break;
550
551 case GL_LUMINANCE:
552 multConst[X] = 1;
553 multConst[Y] = 0;
554 multConst[Z] = 0;
555 multConst[W] = 0;
556 addConst[X] = 0;
557 addConst[Y] = 0;
558 addConst[Z] = 0;
559 addConst[W] = 1;
560 break;
561
562 case GL_LUMINANCE_ALPHA:
563 multConst[X] = 1;
564 multConst[Y] = 0;
565 multConst[Z] = 0;
566 multConst[W] = 1;
567 addConst[X] = 0;
568 addConst[Y] = 0;
569 addConst[Z] = 0;
570 addConst[W] = 0;
571 break;
572
573 default:
574 UNREACHABLE();
575 }
576
577 mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
578
579 return angle::Result::Continue;
580 }
581
copySurfaceToTexture(Context9 * context9,IDirect3DSurface9 * surface,const RECT & sourceRect,angle::ComPtr<IDirect3DBaseTexture9> * outTexture)582 angle::Result Blit9::copySurfaceToTexture(Context9 *context9,
583 IDirect3DSurface9 *surface,
584 const RECT &sourceRect,
585 angle::ComPtr<IDirect3DBaseTexture9> *outTexture)
586 {
587 ASSERT(surface);
588
589 IDirect3DDevice9 *device = mRenderer->getDevice();
590
591 D3DSURFACE_DESC sourceDesc;
592 surface->GetDesc(&sourceDesc);
593
594 // Copy the render target into a texture
595 angle::ComPtr<IDirect3DTexture9> texture;
596 HRESULT result = device->CreateTexture(
597 sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1,
598 D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr);
599 ANGLE_TRY_HR(context9, result, "Failed to allocate internal texture for blit");
600
601 angle::ComPtr<IDirect3DSurface9> textureSurface;
602 result = texture->GetSurfaceLevel(0, &textureSurface);
603 ANGLE_TRY_HR(context9, result, "Failed to query surface of internal blit texture");
604
605 mRenderer->endScene();
606 result = device->StretchRect(surface, &sourceRect, textureSurface.Get(), nullptr, D3DTEXF_NONE);
607 ANGLE_TRY_HR(context9, result, "Failed to copy between internal blit textures");
608 *outTexture = texture;
609
610 return angle::Result::Continue;
611 }
612
setViewportAndShaderConstants(const RECT & sourceRect,const gl::Extents & sourceSize,const RECT & destRect,bool flipY)613 void Blit9::setViewportAndShaderConstants(const RECT &sourceRect,
614 const gl::Extents &sourceSize,
615 const RECT &destRect,
616 bool flipY)
617 {
618 IDirect3DDevice9 *device = mRenderer->getDevice();
619
620 D3DVIEWPORT9 vp;
621 vp.X = destRect.left;
622 vp.Y = destRect.top;
623 vp.Width = destRect.right - destRect.left;
624 vp.Height = destRect.bottom - destRect.top;
625 vp.MinZ = 0.0f;
626 vp.MaxZ = 1.0f;
627 device->SetViewport(&vp);
628
629 float vertexConstants[8] = {
630 // halfPixelAdjust
631 -1.0f / vp.Width,
632 1.0f / vp.Height,
633 0,
634 0,
635 // texcoordOffset
636 static_cast<float>(sourceRect.left) / sourceSize.width,
637 static_cast<float>(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height,
638 static_cast<float>(sourceRect.right - sourceRect.left) / sourceSize.width,
639 static_cast<float>(flipY ? sourceRect.top - sourceRect.bottom
640 : sourceRect.bottom - sourceRect.top) /
641 sourceSize.height,
642 };
643
644 device->SetVertexShaderConstantF(0, vertexConstants, 2);
645 }
646
setCommonBlitState()647 void Blit9::setCommonBlitState()
648 {
649 IDirect3DDevice9 *device = mRenderer->getDevice();
650
651 device->SetDepthStencilSurface(nullptr);
652
653 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
654 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
655 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
656 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
657 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
658 device->SetRenderState(D3DRS_COLORWRITEENABLE,
659 D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE |
660 D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
661 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
662 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
663
664 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
665 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
666 device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
667 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
668 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
669
670 RECT scissorRect = {}; // Scissoring is disabled for flipping, but we need this to capture and
671 // restore the old rectangle
672 device->SetScissorRect(&scissorRect);
673
674 for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
675 {
676 device->SetStreamSourceFreq(i, 1);
677 }
678 }
679
render()680 void Blit9::render()
681 {
682 IDirect3DDevice9 *device = mRenderer->getDevice();
683
684 device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
685 device->SetVertexDeclaration(mQuadVertexDeclaration);
686
687 mRenderer->startScene();
688 device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
689 }
690
saveState()691 void Blit9::saveState()
692 {
693 IDirect3DDevice9 *device = mRenderer->getDevice();
694
695 HRESULT hr;
696
697 device->GetDepthStencilSurface(&mSavedDepthStencil);
698 device->GetRenderTarget(0, &mSavedRenderTarget);
699
700 if (mSavedStateBlock == nullptr)
701 {
702 hr = device->BeginStateBlock();
703 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
704
705 setCommonBlitState();
706
707 static const float mockConst[8] = {0};
708
709 device->SetVertexShader(nullptr);
710 device->SetVertexShaderConstantF(0, mockConst, 2);
711 device->SetPixelShader(nullptr);
712 device->SetPixelShaderConstantF(0, mockConst, 2);
713
714 D3DVIEWPORT9 mockVp;
715 mockVp.X = 0;
716 mockVp.Y = 0;
717 mockVp.Width = 1;
718 mockVp.Height = 1;
719 mockVp.MinZ = 0;
720 mockVp.MaxZ = 1;
721
722 device->SetViewport(&mockVp);
723
724 device->SetTexture(0, nullptr);
725
726 device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
727
728 device->SetVertexDeclaration(mQuadVertexDeclaration);
729
730 hr = device->EndStateBlock(&mSavedStateBlock);
731 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
732 }
733
734 ASSERT(mSavedStateBlock != nullptr);
735
736 if (mSavedStateBlock != nullptr)
737 {
738 hr = mSavedStateBlock->Capture();
739 ASSERT(SUCCEEDED(hr));
740 }
741 }
742
restoreState()743 void Blit9::restoreState()
744 {
745 IDirect3DDevice9 *device = mRenderer->getDevice();
746
747 device->SetDepthStencilSurface(mSavedDepthStencil);
748 SafeRelease(mSavedDepthStencil);
749
750 device->SetRenderTarget(0, mSavedRenderTarget);
751 SafeRelease(mSavedRenderTarget);
752
753 ASSERT(mSavedStateBlock != nullptr);
754
755 if (mSavedStateBlock != nullptr)
756 {
757 mSavedStateBlock->Apply();
758 }
759 }
760 } // namespace rx
761