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
// Blit.cpp: Surface copy utility class.
9
#include "libGLESv2/Blit.h"
11
#include "common/debug.h"
13
#include "libGLESv2/main.h"
14
#include "libGLESv2/utilities.h"
18
#include "libGLESv2/shaders/standardvs.h"
19
#include "libGLESv2/shaders/flipyvs.h"
20
#include "libGLESv2/shaders/passthroughps.h"
21
#include "libGLESv2/shaders/luminanceps.h"
22
#include "libGLESv2/shaders/componentmaskps.h"
24
const BYTE* const g_shaderCode[] =
30
g_ps20_componentmaskps
33
const size_t g_shaderSize[] =
35
sizeof(g_vs20_standardvs),
36
sizeof(g_vs20_flipyvs),
37
sizeof(g_ps20_passthroughps),
38
sizeof(g_ps20_luminanceps),
39
sizeof(g_ps20_componentmaskps)
45
Blit::Blit(Context *context)
46
: mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL), mSavedStateBlock(NULL)
49
memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
54
if (mSavedStateBlock) mSavedStateBlock->Release();
55
if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
56
if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
58
for (int i = 0; i < SHADER_COUNT; i++)
60
if (mCompiledShaders[i])
62
mCompiledShaders[i]->Release();
67
void Blit::initGeometry()
69
static const float quad[] =
77
IDirect3DDevice9 *device = getDevice();
79
HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
83
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
84
return error(GL_OUT_OF_MEMORY);
88
result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
90
if (FAILED(result) || lockPtr == NULL)
92
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
93
return error(GL_OUT_OF_MEMORY);
96
memcpy(lockPtr, quad, sizeof(quad));
97
mQuadVertexBuffer->Unlock();
99
static const D3DVERTEXELEMENT9 elements[] =
101
{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
105
result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
109
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
110
return error(GL_OUT_OF_MEMORY);
114
template <class D3DShaderType>
115
bool Blit::setShader(ShaderId source, const char *profile,
116
D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length),
117
HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
119
egl::Display *display = getDisplay();
120
IDirect3DDevice9 *device = display->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 = (display->*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 Blit::setVertexShader(ShaderId shader)
156
return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &egl::Display::createVertexShader, &IDirect3DDevice9::SetVertexShader);
159
bool Blit::setPixelShader(ShaderId shader)
161
return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &egl::Display::createPixelShader, &IDirect3DDevice9::SetPixelShader);
164
RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
166
D3DSURFACE_DESC desc;
167
surface->GetDesc(&desc);
172
rect.right = desc.Width;
173
rect.bottom = desc.Height;
178
bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
180
IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
186
IDirect3DDevice9 *device = 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);
211
bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
213
IDirect3DDevice9 *device = getDevice();
215
D3DSURFACE_DESC sourceDesc;
216
D3DSURFACE_DESC destDesc;
217
source->GetDesc(&sourceDesc);
218
dest->GetDesc(&destDesc);
220
if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
221
dx2es::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect
223
RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
224
HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
228
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
229
return error(GL_OUT_OF_MEMORY, false);
234
return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
240
bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
242
IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
248
IDirect3DDevice9 *device = getDevice();
252
device->SetTexture(0, texture);
253
device->SetRenderTarget(0, dest);
255
setViewport(sourceRect, xoffset, yoffset);
257
setCommonBlitState();
258
if (setFormatConvertShaders(destFormat))
270
bool Blit::setFormatConvertShaders(GLenum destFormat)
272
bool okay = setVertexShader(SHADER_VS_STANDARD);
276
default: UNREACHABLE();
281
okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
285
case GL_LUMINANCE_ALPHA:
286
okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
295
enum { X = 0, Y = 1, Z = 2, W = 3 };
297
// The meaning of this constant depends on the shader that was selected.
298
// See the shader assembly code above for details.
299
float psConst0[4] = { 0, 0, 0, 0 };
303
default: UNREACHABLE();
323
case GL_LUMINANCE_ALPHA:
328
getDevice()->SetPixelShaderConstantF(0, psConst0, 1);
333
IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
340
egl::Display *display = getDisplay();
341
IDirect3DDevice9 *device = getDevice();
343
D3DSURFACE_DESC sourceDesc;
344
surface->GetDesc(&sourceDesc);
346
// Copy the render target into a texture
347
IDirect3DTexture9 *texture;
348
HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
352
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
353
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
356
IDirect3DSurface9 *textureSurface;
357
result = texture->GetSurfaceLevel(0, &textureSurface);
361
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
363
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
367
result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
369
textureSurface->Release();
373
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
375
return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
381
void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
383
IDirect3DDevice9 *device = getDevice();
388
vp.Width = sourceRect.right - sourceRect.left;
389
vp.Height = sourceRect.bottom - sourceRect.top;
392
device->SetViewport(&vp);
394
float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
395
device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
398
void Blit::setCommonBlitState()
400
IDirect3DDevice9 *device = getDevice();
402
device->SetDepthStencilSurface(NULL);
404
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
405
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
406
device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
407
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
408
device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
409
device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
410
device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
411
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
413
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
414
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
415
device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
416
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
417
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
419
RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
420
device->SetScissorRect(&scissorRect);
422
for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
424
device->SetStreamSourceFreq(i, 1);
430
egl::Display *display = getDisplay();
431
IDirect3DDevice9 *device = getDevice();
433
HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
434
hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
436
display->startScene();
437
hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
440
void Blit::saveState()
442
IDirect3DDevice9 *device = getDevice();
446
device->GetDepthStencilSurface(&mSavedDepthStencil);
447
device->GetRenderTarget(0, &mSavedRenderTarget);
449
if (mSavedStateBlock == NULL)
451
hr = device->BeginStateBlock();
452
ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
454
setCommonBlitState();
456
static const float dummyConst[4] = { 0, 0, 0, 0 };
458
device->SetVertexShader(NULL);
459
device->SetVertexShaderConstantF(0, dummyConst, 1);
460
device->SetPixelShader(NULL);
461
device->SetPixelShaderConstantF(0, dummyConst, 1);
463
D3DVIEWPORT9 dummyVp;
471
device->SetViewport(&dummyVp);
473
device->SetTexture(0, NULL);
475
device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
477
device->SetVertexDeclaration(mQuadVertexDeclaration);
479
hr = device->EndStateBlock(&mSavedStateBlock);
480
ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
483
ASSERT(mSavedStateBlock != NULL);
485
if (mSavedStateBlock != NULL)
487
hr = mSavedStateBlock->Capture();
488
ASSERT(SUCCEEDED(hr));
492
void Blit::restoreState()
494
IDirect3DDevice9 *device = getDevice();
496
device->SetDepthStencilSurface(mSavedDepthStencil);
497
if (mSavedDepthStencil != NULL)
499
mSavedDepthStencil->Release();
500
mSavedDepthStencil = NULL;
503
device->SetRenderTarget(0, mSavedRenderTarget);
504
if (mSavedRenderTarget != NULL)
506
mSavedRenderTarget->Release();
507
mSavedRenderTarget = NULL;
510
ASSERT(mSavedStateBlock != NULL);
512
if (mSavedStateBlock != NULL)
514
mSavedStateBlock->Apply();