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 20namespace rx 21{ 22TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage) 23 : mLodOffset(0), 24 mRenderer(Renderer9::makeRenderer9(renderer)), 25 mD3DUsage(usage), 26 mD3DPool(mRenderer->getTexturePool(usage)) 27{ 28} 29 30TextureStorage9::~TextureStorage9() 31{ 32} 33 34TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) 35{ 36 ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage)); 37 return static_cast<TextureStorage9*>(storage); 38} 39 40DWORD 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 55bool 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 81bool TextureStorage9::isRenderTarget() const 82{ 83 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; 84} 85 86bool TextureStorage9::isManaged() const 87{ 88 return (mD3DPool == D3DPOOL_MANAGED); 89} 90 91D3DPOOL TextureStorage9::getPool() const 92{ 93 return mD3DPool; 94} 95 96DWORD TextureStorage9::getUsage() const 97{ 98 return mD3DUsage; 99} 100 101int TextureStorage9::getLodOffset() const 102{ 103 return mLodOffset; 104} 105 106int TextureStorage9::levelCount() 107{ 108 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0; 109} 110 111TextureStorage9_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 120TextureStorage9_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 144TextureStorage9_2D::~TextureStorage9_2D() 145{ 146 if (mTexture) 147 { 148 mTexture->Release(); 149 } 150 151 delete mRenderTarget; 152} 153 154TextureStorage9_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 162IDirect3DSurface9 *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 181RenderTarget *TextureStorage9_2D::getRenderTarget() 182{ 183 return mRenderTarget; 184} 185 186void 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 200IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const 201{ 202 return mTexture; 203} 204 205void 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 217TextureStorage9_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 246TextureStorage9_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 259TextureStorage9_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 267IDirect3DSurface9 *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 287RenderTarget *TextureStorage9_Cube::getRenderTarget(GLenum faceTarget) 288{ 289 return mRenderTarget[gl::TextureCubeMap::faceIndex(faceTarget)]; 290} 291 292void 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 306IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const 307{ 308 return mTexture; 309} 310 311void 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}