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