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 }