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