Home | History | Annotate | Download | only in renderer
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 2012 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 // TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
      9 // classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
     10 // D3D9 texture.
     11 
     12 #include "libGLESv2/main.h"
     13 #include "libGLESv2/renderer/Renderer9.h"
     14 #include "libGLESv2/renderer/TextureStorage9.h"
     15 #include "libGLESv2/renderer/SwapChain9.h"
     16 #include "libGLESv2/renderer/RenderTarget9.h"
     17 #include "libGLESv2/renderer/renderer9_utils.h"
     18 #include "libGLESv2/Texture.h"
     19 
     20 namespace rx
     21 {
     22 TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
     23     : mLodOffset(0),
     24       mRenderer(Renderer9::makeRenderer9(renderer)),
     25       mD3DUsage(usage),
     26       mD3DPool(mRenderer->getTexturePool(usage))
     27 {
     28 }
     29 
     30 TextureStorage9::~TextureStorage9()
     31 {
     32 }
     33 
     34 TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
     35 {
     36     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
     37     return static_cast<TextureStorage9*>(storage);
     38 }
     39 
     40 DWORD TextureStorage9::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
     41 {
     42     DWORD d3dusage = 0;
     43 
     44     if (d3dfmt == D3DFMT_INTZ)
     45     {
     46         d3dusage |= D3DUSAGE_DEPTHSTENCIL;
     47     }
     48     else if(forceRenderable || (TextureStorage9::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
     49     {
     50         d3dusage |= D3DUSAGE_RENDERTARGET;
     51     }
     52     return d3dusage;
     53 }
     54 
     55 bool TextureStorage9::IsTextureFormatRenderable(D3DFORMAT format)
     56 {
     57     if (format == D3DFMT_INTZ)
     58     {
     59         return true;
     60     }
     61     switch(format)
     62     {
     63       case D3DFMT_L8:
     64       case D3DFMT_A8L8:
     65       case D3DFMT_DXT1:
     66       case D3DFMT_DXT3:
     67       case D3DFMT_DXT5:
     68         return false;
     69       case D3DFMT_A8R8G8B8:
     70       case D3DFMT_X8R8G8B8:
     71       case D3DFMT_A16B16G16R16F:
     72       case D3DFMT_A32B32G32R32F:
     73         return true;
     74       default:
     75         UNREACHABLE();
     76     }
     77 
     78     return false;
     79 }
     80 
     81 bool TextureStorage9::isRenderTarget() const
     82 {
     83     return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
     84 }
     85 
     86 bool TextureStorage9::isManaged() const
     87 {
     88     return (mD3DPool == D3DPOOL_MANAGED);
     89 }
     90 
     91 D3DPOOL TextureStorage9::getPool() const
     92 {
     93     return mD3DPool;
     94 }
     95 
     96 DWORD TextureStorage9::getUsage() const
     97 {
     98     return mD3DUsage;
     99 }
    100 
    101 int TextureStorage9::getLodOffset() const
    102 {
    103     return mLodOffset;
    104 }
    105 
    106 int TextureStorage9::levelCount()
    107 {
    108     return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
    109 }
    110 
    111 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
    112 {
    113     IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
    114     mTexture = surfaceTexture;
    115     mRenderTarget = NULL;
    116 
    117     initializeRenderTarget();
    118 }
    119 
    120 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
    121     : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
    122 {
    123     mTexture = NULL;
    124     mRenderTarget = NULL;
    125     // if the width or height is not positive this should be treated as an incomplete texture
    126     // we handle that here by skipping the d3d texture creation
    127     if (width > 0 && height > 0)
    128     {
    129         IDirect3DDevice9 *device = mRenderer->getDevice();
    130         gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
    131         HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
    132                                                mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
    133 
    134         if (FAILED(result))
    135         {
    136             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
    137             gl::error(GL_OUT_OF_MEMORY);
    138         }
    139     }
    140 
    141     initializeRenderTarget();
    142 }
    143 
    144 TextureStorage9_2D::~TextureStorage9_2D()
    145 {
    146     if (mTexture)
    147     {
    148         mTexture->Release();
    149     }
    150 
    151     delete mRenderTarget;
    152 }
    153 
    154 TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
    155 {
    156     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
    157     return static_cast<TextureStorage9_2D*>(storage);
    158 }
    159 
    160 // Increments refcount on surface.
    161 // caller must Release() the returned surface
    162 IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty)
    163 {
    164     IDirect3DSurface9 *surface = NULL;
    165 
    166     if (mTexture)
    167     {
    168         HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
    169         ASSERT(SUCCEEDED(result));
    170 
    171         // With managed textures the driver needs to be informed of updates to the lower mipmap levels
    172         if (level + mLodOffset != 0 && isManaged() && dirty)
    173         {
    174             mTexture->AddDirtyRect(NULL);
    175         }
    176     }
    177 
    178     return surface;
    179 }
    180 
    181 RenderTarget *TextureStorage9_2D::getRenderTarget()
    182 {
    183     return mRenderTarget;
    184 }
    185 
    186 void TextureStorage9_2D::generateMipmap(int level)
    187 {
    188     IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
    189     IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
    190 
    191     if (upper != NULL && lower != NULL)
    192     {
    193         mRenderer->boxFilter(upper, lower);
    194     }
    195 
    196     if (upper != NULL) upper->Release();
    197     if (lower != NULL) lower->Release();
    198 }
    199 
    200 IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const
    201 {
    202     return mTexture;
    203 }
    204 
    205 void TextureStorage9_2D::initializeRenderTarget()
    206 {
    207     ASSERT(mRenderTarget == NULL);
    208 
    209     if (mTexture != NULL && isRenderTarget())
    210     {
    211         IDirect3DSurface9 *surface = getSurfaceLevel(0, false);
    212 
    213         mRenderTarget = new RenderTarget9(mRenderer, surface);
    214     }
    215 }
    216 
    217 TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
    218     : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
    219 {
    220     mTexture = NULL;
    221     for (int i = 0; i < 6; ++i)
    222     {
    223         mRenderTarget[i] = NULL;
    224     }
    225 
    226     // if the size is not positive this should be treated as an incomplete texture
    227     // we handle that here by skipping the d3d texture creation
    228     if (size > 0)
    229     {
    230         IDirect3DDevice9 *device = mRenderer->getDevice();
    231         int height = size;
    232         gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
    233         HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
    234                                                    mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
    235 
    236         if (FAILED(result))
    237         {
    238             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
    239             gl::error(GL_OUT_OF_MEMORY);
    240         }
    241     }
    242 
    243     initializeRenderTarget();
    244 }
    245 
    246 TextureStorage9_Cube::~TextureStorage9_Cube()
    247 {
    248     if (mTexture)
    249     {
    250         mTexture->Release();
    251     }
    252 
    253     for (int i = 0; i < 6; ++i)
    254     {
    255         delete mRenderTarget[i];
    256     }
    257 }
    258 
    259 TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
    260 {
    261     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
    262     return static_cast<TextureStorage9_Cube*>(storage);
    263 }
    264 
    265 // Increments refcount on surface.
    266 // caller must Release() the returned surface
    267 IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
    268 {
    269     IDirect3DSurface9 *surface = NULL;
    270 
    271     if (mTexture)
    272     {
    273         D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
    274         HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
    275         ASSERT(SUCCEEDED(result));
    276 
    277         // With managed textures the driver needs to be informed of updates to the lower mipmap levels
    278         if (level != 0 && isManaged() && dirty)
    279         {
    280             mTexture->AddDirtyRect(face, NULL);
    281         }
    282     }
    283 
    284     return surface;
    285 }
    286 
    287 RenderTarget *TextureStorage9_Cube::getRenderTarget(GLenum faceTarget)
    288 {
    289     return mRenderTarget[gl::TextureCubeMap::faceIndex(faceTarget)];
    290 }
    291 
    292 void TextureStorage9_Cube::generateMipmap(int face, int level)
    293 {
    294     IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
    295     IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
    296 
    297     if (upper != NULL && lower != NULL)
    298     {
    299         mRenderer->boxFilter(upper, lower);
    300     }
    301 
    302     if (upper != NULL) upper->Release();
    303     if (lower != NULL) lower->Release();
    304 }
    305 
    306 IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const
    307 {
    308     return mTexture;
    309 }
    310 
    311 void TextureStorage9_Cube::initializeRenderTarget()
    312 {
    313     if (mTexture != NULL && isRenderTarget())
    314     {
    315         IDirect3DSurface9 *surface = NULL;
    316 
    317         for (int i = 0; i < 6; ++i)
    318         {
    319             ASSERT(mRenderTarget[i] == NULL);
    320 
    321             surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false);
    322 
    323             mRenderTarget[i] = new RenderTarget9(mRenderer, surface);
    324         }
    325     }
    326 }
    327 
    328 }