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 }