Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / d3d9 / Blit9.cpp
1 //
2 // Copyright (c) 2002-2010 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 "libGLESv2/renderer/d3d/d3d9/Blit9.h"
10 #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h"
11 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h"
12 #include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h"
13 #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h"
14 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h"
15 #include "libGLESv2/Framebuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/main.h"
18
19 namespace
20 {
21 // Precompiled shaders
22 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h"
23 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h"
24 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h"
25 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h"
26 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h"
27
28 const BYTE* const g_shaderCode[] =
29 {
30     g_vs20_standardvs,
31     g_vs20_flipyvs,
32     g_ps20_passthroughps,
33     g_ps20_luminanceps,
34     g_ps20_componentmaskps
35 };
36
37 const size_t g_shaderSize[] =
38 {
39     sizeof(g_vs20_standardvs),
40     sizeof(g_vs20_flipyvs),
41     sizeof(g_ps20_passthroughps),
42     sizeof(g_ps20_luminanceps),
43     sizeof(g_ps20_componentmaskps)
44 };
45 }
46
47 namespace rx
48 {
49 Blit9::Blit9(rx::Renderer9 *renderer)
50   : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL)
51 {
52     initGeometry();
53     memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
54 }
55
56 Blit9::~Blit9()
57 {
58     SafeRelease(mSavedStateBlock);
59     SafeRelease(mQuadVertexBuffer);
60     SafeRelease(mQuadVertexDeclaration);
61
62     for (int i = 0; i < SHADER_COUNT; i++)
63     {
64         SafeRelease(mCompiledShaders[i]);
65     }
66 }
67
68 void Blit9::initGeometry()
69 {
70     static const float quad[] =
71     {
72         -1, -1,
73         -1,  1,
74          1, -1,
75          1,  1
76     };
77
78     IDirect3DDevice9 *device = mRenderer->getDevice();
79
80     HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
81
82     if (FAILED(result))
83     {
84         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
85         return gl::error(GL_OUT_OF_MEMORY);
86     }
87
88     void *lockPtr = NULL;
89     result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
90
91     if (FAILED(result) || lockPtr == NULL)
92     {
93         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
94         return gl::error(GL_OUT_OF_MEMORY);
95     }
96
97     memcpy(lockPtr, quad, sizeof(quad));
98     mQuadVertexBuffer->Unlock();
99
100     static const D3DVERTEXELEMENT9 elements[] =
101     {
102         { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
103         D3DDECL_END()
104     };
105
106     result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
107
108     if (FAILED(result))
109     {
110         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
111         return gl::error(GL_OUT_OF_MEMORY);
112     }
113 }
114
115 template <class D3DShaderType>
116 bool Blit9::setShader(ShaderId source, const char *profile,
117                      D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length),
118                      HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
119 {
120     IDirect3DDevice9 *device = mRenderer->getDevice();
121
122     D3DShaderType *shader;
123
124     if (mCompiledShaders[source] != NULL)
125     {
126         shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
127     }
128     else
129     {
130         const BYTE* shaderCode = g_shaderCode[source];
131         size_t shaderSize = g_shaderSize[source];
132
133         shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize);
134         if (!shader)
135         {
136             ERR("Failed to create shader for blit operation");
137             return false;
138         }
139
140         mCompiledShaders[source] = shader;
141     }
142
143     HRESULT hr = (device->*setShader)(shader);
144
145     if (FAILED(hr))
146     {
147         ERR("Failed to set shader for blit operation");
148         return false;
149     }
150
151     return true;
152 }
153
154 bool Blit9::setVertexShader(ShaderId shader)
155 {
156     return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
157 }
158
159 bool Blit9::setPixelShader(ShaderId shader)
160 {
161     return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
162 }
163
164 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
165 {
166     D3DSURFACE_DESC desc;
167     surface->GetDesc(&desc);
168
169     RECT rect;
170     rect.left = 0;
171     rect.top = 0;
172     rect.right = desc.Width;
173     rect.bottom = desc.Height;
174
175     return rect;
176 }
177
178 bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
179 {
180     IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
181     if (!texture)
182     {
183         return false;
184     }
185
186     IDirect3DDevice9 *device = mRenderer->getDevice();
187
188     saveState();
189
190     device->SetTexture(0, texture);
191     device->SetRenderTarget(0, dest);
192
193     setVertexShader(SHADER_VS_STANDARD);
194     setPixelShader(SHADER_PS_PASSTHROUGH);
195
196     setCommonBlitState();
197     device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
198     device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
199
200     setViewport(getSurfaceRect(dest), 0, 0);
201
202     render();
203
204     SafeRelease(texture);
205
206     restoreState();
207
208     return true;
209 }
210
211 bool Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level)
212 {
213     RenderTarget9 *renderTarget = NULL;
214     IDirect3DSurface9 *source = NULL;
215     gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
216
217     if (colorbuffer)
218     {
219         renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
220     }
221
222     if (renderTarget)
223     {
224         source = renderTarget->getSurface();
225     }
226
227     if (!source)
228     {
229         ERR("Failed to retrieve the render target.");
230         return gl::error(GL_OUT_OF_MEMORY, false);
231     }
232
233     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
234     IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true);
235     bool result = false;
236
237     if (destSurface)
238     {
239         result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
240         SafeRelease(destSurface);
241     }
242
243     SafeRelease(source);
244     return result;
245 }
246
247 bool Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level)
248 {
249     RenderTarget9 *renderTarget = NULL;
250     IDirect3DSurface9 *source = NULL;
251     gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
252
253     if (colorbuffer)
254     {
255         renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
256     }
257
258     if (renderTarget)
259     {
260         source = renderTarget->getSurface();
261     }
262
263     if (!source)
264     {
265         ERR("Failed to retrieve the render target.");
266         return gl::error(GL_OUT_OF_MEMORY, false);
267     }
268
269     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
270     IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true);
271     bool result = false;
272
273     if (destSurface)
274     {
275         result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
276         SafeRelease(destSurface);
277     }
278
279     SafeRelease(source);
280     return result;
281 }
282
283 bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
284 {
285     if (!dest)
286     {
287         return false;
288     }
289
290     IDirect3DDevice9 *device = mRenderer->getDevice();
291
292     D3DSURFACE_DESC sourceDesc;
293     D3DSURFACE_DESC destDesc;
294     source->GetDesc(&sourceDesc);
295     dest->GetDesc(&destDesc);
296
297     if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
298         d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat))   // Can use StretchRect
299     {
300         RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
301         HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
302
303         if (FAILED(result))
304         {
305             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
306             return gl::error(GL_OUT_OF_MEMORY, false);
307         }
308     }
309     else
310     {
311         return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
312     }
313     return true;
314 }
315
316 bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
317 {
318     IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
319     if (!texture)
320     {
321         return false;
322     }
323
324     IDirect3DDevice9 *device = mRenderer->getDevice();
325
326     saveState();
327
328     device->SetTexture(0, texture);
329     device->SetRenderTarget(0, dest);
330
331     setViewport(sourceRect, xoffset, yoffset);
332
333     setCommonBlitState();
334     if (setFormatConvertShaders(destFormat))
335     {
336         render();
337     }
338
339     SafeRelease(texture);
340
341     restoreState();
342
343     return true;
344 }
345
346 bool Blit9::setFormatConvertShaders(GLenum destFormat)
347 {
348     bool okay = setVertexShader(SHADER_VS_STANDARD);
349
350     switch (destFormat)
351     {
352       default: UNREACHABLE();
353       case GL_RGBA:
354       case GL_BGRA_EXT:
355       case GL_RGB:
356       case GL_RG_EXT:
357       case GL_RED_EXT:
358       case GL_ALPHA:
359         okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
360         break;
361
362       case GL_LUMINANCE:
363       case GL_LUMINANCE_ALPHA:
364         okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
365         break;
366     }
367
368     if (!okay)
369     {
370         return false;
371     }
372
373     enum { X = 0, Y = 1, Z = 2, W = 3 };
374
375     // The meaning of this constant depends on the shader that was selected.
376     // See the shader assembly code above for details.
377     // Allocate one array for both registers and split it into two float4's.
378     float psConst[8] = { 0 };
379     float *multConst = &psConst[0];
380     float *addConst = &psConst[4];
381
382     switch (destFormat)
383     {
384       default: UNREACHABLE();
385       case GL_RGBA:
386       case GL_BGRA_EXT:
387         multConst[X] = 1;
388         multConst[Y] = 1;
389         multConst[Z] = 1;
390         multConst[W] = 1;
391         addConst[X] = 0;
392         addConst[Y] = 0;
393         addConst[Z] = 0;
394         addConst[W] = 0;
395         break;
396
397       case GL_RGB:
398         multConst[X] = 1;
399         multConst[Y] = 1;
400         multConst[Z] = 1;
401         multConst[W] = 0;
402         addConst[X] = 0;
403         addConst[Y] = 0;
404         addConst[Z] = 0;
405         addConst[W] = 1;
406         break;
407
408       case GL_RG_EXT:
409         multConst[X] = 1;
410         multConst[Y] = 1;
411         multConst[Z] = 0;
412         multConst[W] = 0;
413         addConst[X] = 0;
414         addConst[Y] = 0;
415         addConst[Z] = 0;
416         addConst[W] = 1;
417         break;
418
419       case GL_RED_EXT:
420         multConst[X] = 1;
421         multConst[Y] = 0;
422         multConst[Z] = 0;
423         multConst[W] = 0;
424         addConst[X] = 0;
425         addConst[Y] = 0;
426         addConst[Z] = 0;
427         addConst[W] = 1;
428         break;
429
430       case GL_ALPHA:
431         multConst[X] = 0;
432         multConst[Y] = 0;
433         multConst[Z] = 0;
434         multConst[W] = 1;
435         addConst[X] = 0;
436         addConst[Y] = 0;
437         addConst[Z] = 0;
438         addConst[W] = 0;
439         break;
440
441       case GL_LUMINANCE:
442         multConst[X] = 1;
443         multConst[Y] = 0;
444         multConst[Z] = 0;
445         multConst[W] = 0;
446         addConst[X] = 0;
447         addConst[Y] = 0;
448         addConst[Z] = 0;
449         addConst[W] = 1;
450         break;
451
452       case GL_LUMINANCE_ALPHA:
453         multConst[X] = 1;
454         multConst[Y] = 0;
455         multConst[Z] = 0;
456         multConst[W] = 1;
457         addConst[X] = 0;
458         addConst[Y] = 0;
459         addConst[Z] = 0;
460         addConst[W] = 0;
461         break;
462     }
463
464     mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
465
466     return true;
467 }
468
469 IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
470 {
471     if (!surface)
472     {
473         return NULL;
474     }
475
476     IDirect3DDevice9 *device = mRenderer->getDevice();
477
478     D3DSURFACE_DESC sourceDesc;
479     surface->GetDesc(&sourceDesc);
480
481     // Copy the render target into a texture
482     IDirect3DTexture9 *texture;
483     HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
484
485     if (FAILED(result))
486     {
487         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
488         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
489     }
490
491     IDirect3DSurface9 *textureSurface;
492     result = texture->GetSurfaceLevel(0, &textureSurface);
493
494     if (FAILED(result))
495     {
496         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
497         SafeRelease(texture);
498         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
499     }
500
501     mRenderer->endScene();
502     result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
503
504     SafeRelease(textureSurface);
505
506     if (FAILED(result))
507     {
508         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
509         SafeRelease(texture);
510         return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
511     }
512
513     return texture;
514 }
515
516 void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
517 {
518     IDirect3DDevice9 *device = mRenderer->getDevice();
519
520     D3DVIEWPORT9 vp;
521     vp.X      = xoffset;
522     vp.Y      = yoffset;
523     vp.Width  = sourceRect.right - sourceRect.left;
524     vp.Height = sourceRect.bottom - sourceRect.top;
525     vp.MinZ   = 0.0f;
526     vp.MaxZ   = 1.0f;
527     device->SetViewport(&vp);
528
529     float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
530     device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
531 }
532
533 void Blit9::setCommonBlitState()
534 {
535     IDirect3DDevice9 *device = mRenderer->getDevice();
536
537     device->SetDepthStencilSurface(NULL);
538
539     device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
540     device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
541     device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
542     device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
543     device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
544     device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
545     device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
546     device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
547
548     device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
549     device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
550     device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
551     device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
552     device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
553
554     RECT scissorRect = {0};   // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
555     device->SetScissorRect(&scissorRect);
556
557     for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
558     {
559         device->SetStreamSourceFreq(i, 1);
560     }
561 }
562
563 void Blit9::render()
564 {
565     IDirect3DDevice9 *device = mRenderer->getDevice();
566
567     HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
568     hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
569
570     mRenderer->startScene();
571     hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
572 }
573
574 void Blit9::saveState()
575 {
576     IDirect3DDevice9 *device = mRenderer->getDevice();
577
578     HRESULT hr;
579
580     device->GetDepthStencilSurface(&mSavedDepthStencil);
581     device->GetRenderTarget(0, &mSavedRenderTarget);
582
583     if (mSavedStateBlock == NULL)
584     {
585         hr = device->BeginStateBlock();
586         ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
587
588         setCommonBlitState();
589
590         static const float dummyConst[8] = { 0 };
591
592         device->SetVertexShader(NULL);
593         device->SetVertexShaderConstantF(0, dummyConst, 2);
594         device->SetPixelShader(NULL);
595         device->SetPixelShaderConstantF(0, dummyConst, 2);
596
597         D3DVIEWPORT9 dummyVp;
598         dummyVp.X = 0;
599         dummyVp.Y = 0;
600         dummyVp.Width = 1;
601         dummyVp.Height = 1;
602         dummyVp.MinZ = 0;
603         dummyVp.MaxZ = 1;
604
605         device->SetViewport(&dummyVp);
606
607         device->SetTexture(0, NULL);
608
609         device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
610
611         device->SetVertexDeclaration(mQuadVertexDeclaration);
612
613         hr = device->EndStateBlock(&mSavedStateBlock);
614         ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
615     }
616
617     ASSERT(mSavedStateBlock != NULL);
618
619     if (mSavedStateBlock != NULL)
620     {
621         hr = mSavedStateBlock->Capture();
622         ASSERT(SUCCEEDED(hr));
623     }
624 }
625
626 void Blit9::restoreState()
627 {
628     IDirect3DDevice9 *device = mRenderer->getDevice();
629
630     device->SetDepthStencilSurface(mSavedDepthStencil);
631     SafeRelease(mSavedDepthStencil);
632
633     device->SetRenderTarget(0, mSavedRenderTarget);
634     SafeRelease(mSavedRenderTarget);
635
636     ASSERT(mSavedStateBlock != NULL);
637
638     if (mSavedStateBlock != NULL)
639     {
640         mSavedStateBlock->Apply();
641     }
642 }
643
644 }