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     HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
685     hr         = device->SetVertexDeclaration(mQuadVertexDeclaration);
686 
687     mRenderer->startScene();
688     hr = 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