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.
7 // Blit9.cpp: Surface copy utility class.
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"
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"
28 const BYTE* const g_shaderCode[] =
34 g_ps20_componentmaskps
37 const size_t g_shaderSize[] =
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)
49 Blit9::Blit9(rx::Renderer9 *renderer)
50 : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL)
53 memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
58 SafeRelease(mSavedStateBlock);
59 SafeRelease(mQuadVertexBuffer);
60 SafeRelease(mQuadVertexDeclaration);
62 for (int i = 0; i < SHADER_COUNT; i++)
64 SafeRelease(mCompiledShaders[i]);
68 void Blit9::initGeometry()
70 static const float quad[] =
78 IDirect3DDevice9 *device = mRenderer->getDevice();
80 HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
84 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
85 return gl::error(GL_OUT_OF_MEMORY);
89 result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
91 if (FAILED(result) || lockPtr == NULL)
93 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
94 return gl::error(GL_OUT_OF_MEMORY);
97 memcpy(lockPtr, quad, sizeof(quad));
98 mQuadVertexBuffer->Unlock();
100 static const D3DVERTEXELEMENT9 elements[] =
102 { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
106 result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
110 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
111 return gl::error(GL_OUT_OF_MEMORY);
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*))
120 IDirect3DDevice9 *device = mRenderer->getDevice();
122 D3DShaderType *shader;
124 if (mCompiledShaders[source] != NULL)
126 shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
130 const BYTE* shaderCode = g_shaderCode[source];
131 size_t shaderSize = g_shaderSize[source];
133 shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize);
136 ERR("Failed to create shader for blit operation");
140 mCompiledShaders[source] = shader;
143 HRESULT hr = (device->*setShader)(shader);
147 ERR("Failed to set shader for blit operation");
154 bool Blit9::setVertexShader(ShaderId shader)
156 return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
159 bool Blit9::setPixelShader(ShaderId shader)
161 return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
164 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const
166 D3DSURFACE_DESC desc;
167 surface->GetDesc(&desc);
172 rect.right = desc.Width;
173 rect.bottom = desc.Height;
178 bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
180 IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
186 IDirect3DDevice9 *device = mRenderer->getDevice();
190 device->SetTexture(0, texture);
191 device->SetRenderTarget(0, dest);
193 setVertexShader(SHADER_VS_STANDARD);
194 setPixelShader(SHADER_PS_PASSTHROUGH);
196 setCommonBlitState();
197 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
198 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
200 setViewport(getSurfaceRect(dest), 0, 0);
204 SafeRelease(texture);
211 bool Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level)
213 RenderTarget9 *renderTarget = NULL;
214 IDirect3DSurface9 *source = NULL;
215 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
219 renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
224 source = renderTarget->getSurface();
229 ERR("Failed to retrieve the render target.");
230 return gl::error(GL_OUT_OF_MEMORY, false);
233 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
234 IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true);
239 result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
240 SafeRelease(destSurface);
247 bool Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level)
249 RenderTarget9 *renderTarget = NULL;
250 IDirect3DSurface9 *source = NULL;
251 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
255 renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
260 source = renderTarget->getSurface();
265 ERR("Failed to retrieve the render target.");
266 return gl::error(GL_OUT_OF_MEMORY, false);
269 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
270 IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true);
275 result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
276 SafeRelease(destSurface);
283 bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
290 IDirect3DDevice9 *device = mRenderer->getDevice();
292 D3DSURFACE_DESC sourceDesc;
293 D3DSURFACE_DESC destDesc;
294 source->GetDesc(&sourceDesc);
295 dest->GetDesc(&destDesc);
297 if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
298 d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect
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);
305 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
306 return gl::error(GL_OUT_OF_MEMORY, false);
311 return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
316 bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
318 IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
324 IDirect3DDevice9 *device = mRenderer->getDevice();
328 device->SetTexture(0, texture);
329 device->SetRenderTarget(0, dest);
331 setViewport(sourceRect, xoffset, yoffset);
333 setCommonBlitState();
334 if (setFormatConvertShaders(destFormat))
339 SafeRelease(texture);
346 bool Blit9::setFormatConvertShaders(GLenum destFormat)
348 bool okay = setVertexShader(SHADER_VS_STANDARD);
352 default: UNREACHABLE();
359 okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
363 case GL_LUMINANCE_ALPHA:
364 okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
373 enum { X = 0, Y = 1, Z = 2, W = 3 };
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];
384 default: UNREACHABLE();
452 case GL_LUMINANCE_ALPHA:
464 mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2);
469 IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
476 IDirect3DDevice9 *device = mRenderer->getDevice();
478 D3DSURFACE_DESC sourceDesc;
479 surface->GetDesc(&sourceDesc);
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);
487 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
488 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
491 IDirect3DSurface9 *textureSurface;
492 result = texture->GetSurfaceLevel(0, &textureSurface);
496 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
497 SafeRelease(texture);
498 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
501 mRenderer->endScene();
502 result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
504 SafeRelease(textureSurface);
508 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
509 SafeRelease(texture);
510 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
516 void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
518 IDirect3DDevice9 *device = mRenderer->getDevice();
523 vp.Width = sourceRect.right - sourceRect.left;
524 vp.Height = sourceRect.bottom - sourceRect.top;
527 device->SetViewport(&vp);
529 float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
530 device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
533 void Blit9::setCommonBlitState()
535 IDirect3DDevice9 *device = mRenderer->getDevice();
537 device->SetDepthStencilSurface(NULL);
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);
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);
554 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
555 device->SetScissorRect(&scissorRect);
557 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
559 device->SetStreamSourceFreq(i, 1);
565 IDirect3DDevice9 *device = mRenderer->getDevice();
567 HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
568 hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
570 mRenderer->startScene();
571 hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
574 void Blit9::saveState()
576 IDirect3DDevice9 *device = mRenderer->getDevice();
580 device->GetDepthStencilSurface(&mSavedDepthStencil);
581 device->GetRenderTarget(0, &mSavedRenderTarget);
583 if (mSavedStateBlock == NULL)
585 hr = device->BeginStateBlock();
586 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
588 setCommonBlitState();
590 static const float dummyConst[8] = { 0 };
592 device->SetVertexShader(NULL);
593 device->SetVertexShaderConstantF(0, dummyConst, 2);
594 device->SetPixelShader(NULL);
595 device->SetPixelShaderConstantF(0, dummyConst, 2);
597 D3DVIEWPORT9 dummyVp;
605 device->SetViewport(&dummyVp);
607 device->SetTexture(0, NULL);
609 device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
611 device->SetVertexDeclaration(mQuadVertexDeclaration);
613 hr = device->EndStateBlock(&mSavedStateBlock);
614 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
617 ASSERT(mSavedStateBlock != NULL);
619 if (mSavedStateBlock != NULL)
621 hr = mSavedStateBlock->Capture();
622 ASSERT(SUCCEEDED(hr));
626 void Blit9::restoreState()
628 IDirect3DDevice9 *device = mRenderer->getDevice();
630 device->SetDepthStencilSurface(mSavedDepthStencil);
631 SafeRelease(mSavedDepthStencil);
633 device->SetRenderTarget(0, mSavedRenderTarget);
634 SafeRelease(mSavedRenderTarget);
636 ASSERT(mSavedStateBlock != NULL);
638 if (mSavedStateBlock != NULL)
640 mSavedStateBlock->Apply();