TextureStorage9.cpp (22084B)
1 // 2 // Copyright 2012 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 "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" 12 13 #include "common/utilities.h" 14 #include "libANGLE/Context.h" 15 #include "libANGLE/Texture.h" 16 #include "libANGLE/formatutils.h" 17 #include "libANGLE/renderer/d3d/EGLImageD3D.h" 18 #include "libANGLE/renderer/d3d/TextureD3D.h" 19 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" 20 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" 21 #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" 22 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" 23 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" 24 25 namespace rx 26 { 27 TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage, const std::string &label) 28 : TextureStorage(label), 29 mTopLevel(0), 30 mMipLevels(0), 31 mTextureWidth(0), 32 mTextureHeight(0), 33 mInternalFormat(GL_NONE), 34 mTextureFormat(D3DFMT_UNKNOWN), 35 mRenderer(renderer), 36 mD3DUsage(usage), 37 mD3DPool(mRenderer->getTexturePool(usage)) 38 {} 39 40 TextureStorage9::~TextureStorage9() {} 41 42 DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) 43 { 44 DWORD d3dusage = 0; 45 46 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); 47 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); 48 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) 49 { 50 d3dusage |= D3DUSAGE_DEPTHSTENCIL; 51 } 52 else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) 53 { 54 d3dusage |= D3DUSAGE_RENDERTARGET; 55 } 56 57 return d3dusage; 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 bool TextureStorage9::supportsNativeMipmapFunction() const 71 { 72 return false; 73 } 74 75 D3DPOOL TextureStorage9::getPool() const 76 { 77 return mD3DPool; 78 } 79 80 DWORD TextureStorage9::getUsage() const 81 { 82 return mD3DUsage; 83 } 84 85 int TextureStorage9::getTopLevel() const 86 { 87 return mTopLevel; 88 } 89 90 int TextureStorage9::getLevelCount() const 91 { 92 return static_cast<int>(mMipLevels) - mTopLevel; 93 } 94 95 angle::Result TextureStorage9::setData(const gl::Context *context, 96 const gl::ImageIndex &index, 97 ImageD3D *image, 98 const gl::Box *destBox, 99 GLenum type, 100 const gl::PixelUnpackState &unpack, 101 const uint8_t *pixelData) 102 { 103 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 104 return angle::Result::Stop; 105 } 106 107 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, 108 SwapChain9 *swapchain, 109 const std::string &label) 110 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET, label) 111 { 112 IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); 113 mTexture = surfaceTexture; 114 mMipLevels = surfaceTexture->GetLevelCount(); 115 116 mInternalFormat = swapchain->getRenderTargetInternalFormat(); 117 118 D3DSURFACE_DESC surfaceDesc; 119 surfaceTexture->GetLevelDesc(0, &surfaceDesc); 120 mTextureWidth = surfaceDesc.Width; 121 mTextureHeight = surfaceDesc.Height; 122 mTextureFormat = surfaceDesc.Format; 123 124 mRenderTargets.resize(mMipLevels, nullptr); 125 } 126 127 TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, 128 GLenum internalformat, 129 bool renderTarget, 130 GLsizei width, 131 GLsizei height, 132 int levels, 133 const std::string &label) 134 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget), label) 135 { 136 mTexture = nullptr; 137 138 mInternalFormat = internalformat; 139 140 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); 141 mTextureFormat = d3dFormatInfo.texFormat; 142 143 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); 144 mTextureWidth = width; 145 mTextureHeight = height; 146 mMipLevels = mTopLevel + levels; 147 148 mRenderTargets.resize(levels, nullptr); 149 } 150 151 TextureStorage9_2D::~TextureStorage9_2D() 152 { 153 SafeRelease(mTexture); 154 for (RenderTargetD3D *renderTarget : mRenderTargets) 155 { 156 SafeDelete(renderTarget); 157 } 158 } 159 160 // Increments refcount on surface. 161 // caller must Release() the returned surface 162 angle::Result TextureStorage9_2D::getSurfaceLevel(const gl::Context *context, 163 gl::TextureTarget target, 164 int level, 165 bool dirty, 166 IDirect3DSurface9 **outSurface) 167 { 168 ASSERT(target == gl::TextureTarget::_2D); 169 170 IDirect3DBaseTexture9 *baseTexture = nullptr; 171 ANGLE_TRY(getBaseTexture(context, &baseTexture)); 172 173 IDirect3DTexture9 *texture = static_cast<IDirect3DTexture9 *>(baseTexture); 174 175 HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); 176 ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); 177 178 // With managed textures the driver needs to be informed of updates to the lower mipmap levels 179 if (level + mTopLevel != 0 && isManaged() && dirty) 180 { 181 texture->AddDirtyRect(nullptr); 182 } 183 184 return angle::Result::Continue; 185 } 186 187 angle::Result TextureStorage9_2D::findRenderTarget(const gl::Context *context, 188 const gl::ImageIndex &index, 189 GLsizei samples, 190 RenderTargetD3D **outRT) const 191 { 192 ASSERT(index.getLevelIndex() < getLevelCount()); 193 194 ASSERT(outRT); 195 *outRT = mRenderTargets[index.getLevelIndex()]; 196 return angle::Result::Continue; 197 } 198 199 angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context, 200 const gl::ImageIndex &index, 201 GLsizei samples, 202 RenderTargetD3D **outRT) 203 { 204 ASSERT(index.getLevelIndex() < getLevelCount()); 205 206 if (!mRenderTargets[index.getLevelIndex()] && isRenderTarget()) 207 { 208 IDirect3DBaseTexture9 *baseTexture = nullptr; 209 ANGLE_TRY(getBaseTexture(context, &baseTexture)); 210 211 IDirect3DSurface9 *surface = nullptr; 212 ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, index.getLevelIndex(), false, 213 &surface)); 214 215 size_t textureMipLevel = mTopLevel + index.getLevelIndex(); 216 size_t mipWidth = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u); 217 size_t mipHeight = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u); 218 219 baseTexture->AddRef(); 220 mRenderTargets[index.getLevelIndex()] = new TextureRenderTarget9( 221 baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth), 222 static_cast<GLsizei>(mipHeight), 1, 0); 223 } 224 225 ASSERT(outRT); 226 *outRT = mRenderTargets[index.getLevelIndex()]; 227 return angle::Result::Continue; 228 } 229 230 angle::Result TextureStorage9_2D::generateMipmap(const gl::Context *context, 231 const gl::ImageIndex &sourceIndex, 232 const gl::ImageIndex &destIndex) 233 { 234 angle::ComPtr<IDirect3DSurface9> upper = nullptr; 235 ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, sourceIndex.getLevelIndex(), false, 236 &upper)); 237 238 angle::ComPtr<IDirect3DSurface9> lower = nullptr; 239 ANGLE_TRY( 240 getSurfaceLevel(context, gl::TextureTarget::_2D, destIndex.getLevelIndex(), true, &lower)); 241 242 ASSERT(upper && lower); 243 return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get()); 244 } 245 246 angle::Result TextureStorage9_2D::getBaseTexture(const gl::Context *context, 247 IDirect3DBaseTexture9 **outTexture) 248 { 249 // if the width or height is not positive this should be treated as an incomplete texture 250 // we handle that here by skipping the d3d texture creation 251 if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) 252 { 253 ASSERT(mMipLevels > 0); 254 255 IDirect3DDevice9 *device = mRenderer->getDevice(); 256 HRESULT result = device->CreateTexture(static_cast<unsigned int>(mTextureWidth), 257 static_cast<unsigned int>(mTextureHeight), 258 static_cast<unsigned int>(mMipLevels), getUsage(), 259 mTextureFormat, getPool(), &mTexture, nullptr); 260 ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create 2D storage texture"); 261 } 262 263 *outTexture = mTexture; 264 return angle::Result::Continue; 265 } 266 267 angle::Result TextureStorage9_2D::copyToStorage(const gl::Context *context, 268 TextureStorage *destStorage) 269 { 270 ASSERT(destStorage); 271 272 TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage); 273 274 int levels = getLevelCount(); 275 for (int i = 0; i < levels; ++i) 276 { 277 angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr; 278 ANGLE_TRY(getSurfaceLevel(context, gl::TextureTarget::_2D, i, false, &srcSurf)); 279 280 angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr; 281 ANGLE_TRY(dest9->getSurfaceLevel(context, gl::TextureTarget::_2D, i, true, &dstSurf)); 282 283 ANGLE_TRY( 284 mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged())); 285 } 286 287 return angle::Result::Continue; 288 } 289 290 TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, 291 EGLImageD3D *image, 292 RenderTarget9 *renderTarget9, 293 const std::string &label) 294 : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET, label), mImage(image) 295 { 296 297 mInternalFormat = renderTarget9->getInternalFormat(); 298 mTextureFormat = renderTarget9->getD3DFormat(); 299 mTextureWidth = renderTarget9->getWidth(); 300 mTextureHeight = renderTarget9->getHeight(); 301 mTopLevel = static_cast<int>(renderTarget9->getTextureLevel()); 302 mMipLevels = mTopLevel + 1; 303 } 304 305 TextureStorage9_EGLImage::~TextureStorage9_EGLImage() {} 306 307 angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context, 308 gl::TextureTarget target, 309 int level, 310 bool, 311 IDirect3DSurface9 **outSurface) 312 { 313 ASSERT(target == gl::TextureTarget::_2D); 314 ASSERT(level == 0); 315 316 RenderTargetD3D *renderTargetD3D = nullptr; 317 ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); 318 319 RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D); 320 321 *outSurface = renderTarget9->getSurface(); 322 return angle::Result::Continue; 323 } 324 325 angle::Result TextureStorage9_EGLImage::findRenderTarget(const gl::Context *context, 326 const gl::ImageIndex &index, 327 GLsizei samples, 328 RenderTargetD3D **outRT) const 329 { 330 // Since the render target of a EGL image will be updated when orphaning, trying to find a cache 331 // of it can be rarely useful. 332 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 333 return angle::Result::Stop; 334 } 335 336 angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context, 337 const gl::ImageIndex &index, 338 GLsizei samples, 339 RenderTargetD3D **outRT) 340 { 341 ASSERT(!index.hasLayer()); 342 ASSERT(index.getLevelIndex() == 0); 343 ASSERT(samples == 0); 344 345 return mImage->getRenderTarget(context, outRT); 346 } 347 348 angle::Result TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context, 349 IDirect3DBaseTexture9 **outTexture) 350 { 351 RenderTargetD3D *renderTargetD3D = nullptr; 352 ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); 353 354 RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D); 355 *outTexture = renderTarget9->getTexture(); 356 ASSERT(*outTexture != nullptr); 357 358 return angle::Result::Continue; 359 } 360 361 angle::Result TextureStorage9_EGLImage::generateMipmap(const gl::Context *context, 362 const gl::ImageIndex &, 363 const gl::ImageIndex &) 364 { 365 ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context)); 366 return angle::Result::Stop; 367 } 368 369 angle::Result TextureStorage9_EGLImage::copyToStorage(const gl::Context *context, 370 TextureStorage *destStorage) 371 { 372 ASSERT(destStorage); 373 ASSERT(getLevelCount() == 1); 374 375 TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage); 376 377 IDirect3DBaseTexture9 *destBaseTexture9 = nullptr; 378 ANGLE_TRY(dest9->getBaseTexture(context, &destBaseTexture9)); 379 380 IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9); 381 382 angle::ComPtr<IDirect3DSurface9> destSurface = nullptr; 383 HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface); 384 ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); 385 386 RenderTargetD3D *sourceRenderTarget = nullptr; 387 ANGLE_TRY(mImage->getRenderTarget(context, &sourceRenderTarget)); 388 389 RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget); 390 ANGLE_TRY(mRenderer->copyToRenderTarget(context, destSurface.Get(), 391 sourceRenderTarget9->getSurface(), isManaged())); 392 393 if (destStorage->getTopLevel() != 0) 394 { 395 destTexture9->AddDirtyRect(nullptr); 396 } 397 398 return angle::Result::Continue; 399 } 400 401 TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, 402 GLenum internalformat, 403 bool renderTarget, 404 int size, 405 int levels, 406 bool hintLevelZeroOnly, 407 const std::string &label) 408 : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget), label) 409 { 410 mTexture = nullptr; 411 for (size_t i = 0; i < gl::kCubeFaceCount; ++i) 412 { 413 mRenderTarget[i] = nullptr; 414 } 415 416 mInternalFormat = internalformat; 417 418 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); 419 mTextureFormat = d3dFormatInfo.texFormat; 420 421 int height = size; 422 d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); 423 mTextureWidth = size; 424 mTextureHeight = size; 425 mMipLevels = mTopLevel + levels; 426 } 427 428 TextureStorage9_Cube::~TextureStorage9_Cube() 429 { 430 SafeRelease(mTexture); 431 432 for (size_t i = 0; i < gl::kCubeFaceCount; ++i) 433 { 434 SafeDelete(mRenderTarget[i]); 435 } 436 } 437 438 // Increments refcount on surface. 439 // caller must Release() the returned surface 440 angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context, 441 gl::TextureTarget target, 442 int level, 443 bool dirty, 444 IDirect3DSurface9 **outSurface) 445 { 446 IDirect3DBaseTexture9 *baseTexture = nullptr; 447 ANGLE_TRY(getBaseTexture(context, &baseTexture)); 448 449 IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9 *>(baseTexture); 450 451 D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target); 452 HRESULT result = texture->GetCubeMapSurface(face, level, outSurface); 453 ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to get the surface from a texture"); 454 455 // With managed textures the driver needs to be informed of updates to the lower mipmap levels 456 if (level != 0 && isManaged() && dirty) 457 { 458 texture->AddDirtyRect(face, nullptr); 459 } 460 461 return angle::Result::Continue; 462 } 463 464 angle::Result TextureStorage9_Cube::findRenderTarget(const gl::Context *context, 465 const gl::ImageIndex &index, 466 GLsizei samples, 467 RenderTargetD3D **outRT) const 468 { 469 ASSERT(outRT); 470 ASSERT(index.getLevelIndex() == 0); 471 ASSERT(samples == 0); 472 473 ASSERT(index.getType() == gl::TextureType::CubeMap && 474 gl::IsCubeMapFaceTarget(index.getTarget())); 475 const size_t renderTargetIndex = index.cubeMapFaceIndex(); 476 477 *outRT = mRenderTarget[renderTargetIndex]; 478 return angle::Result::Continue; 479 } 480 481 angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context, 482 const gl::ImageIndex &index, 483 GLsizei samples, 484 RenderTargetD3D **outRT) 485 { 486 ASSERT(outRT); 487 ASSERT(index.getLevelIndex() == 0); 488 ASSERT(samples == 0); 489 490 ASSERT(index.getType() == gl::TextureType::CubeMap && 491 gl::IsCubeMapFaceTarget(index.getTarget())); 492 const size_t renderTargetIndex = index.cubeMapFaceIndex(); 493 494 if (mRenderTarget[renderTargetIndex] == nullptr && isRenderTarget()) 495 { 496 IDirect3DBaseTexture9 *baseTexture = nullptr; 497 ANGLE_TRY(getBaseTexture(context, &baseTexture)); 498 499 IDirect3DSurface9 *surface = nullptr; 500 ANGLE_TRY(getSurfaceLevel(context, index.getTarget(), mTopLevel + index.getLevelIndex(), 501 false, &surface)); 502 503 baseTexture->AddRef(); 504 mRenderTarget[renderTargetIndex] = new TextureRenderTarget9( 505 baseTexture, mTopLevel + index.getLevelIndex(), surface, mInternalFormat, 506 static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0); 507 } 508 509 *outRT = mRenderTarget[renderTargetIndex]; 510 return angle::Result::Continue; 511 } 512 513 angle::Result TextureStorage9_Cube::generateMipmap(const gl::Context *context, 514 const gl::ImageIndex &sourceIndex, 515 const gl::ImageIndex &destIndex) 516 { 517 angle::ComPtr<IDirect3DSurface9> upper = nullptr; 518 ANGLE_TRY(getSurfaceLevel(context, sourceIndex.getTarget(), sourceIndex.getLevelIndex(), false, 519 &upper)); 520 521 angle::ComPtr<IDirect3DSurface9> lower = nullptr; 522 ANGLE_TRY( 523 getSurfaceLevel(context, destIndex.getTarget(), destIndex.getLevelIndex(), true, &lower)); 524 525 ASSERT(upper && lower); 526 return mRenderer->boxFilter(GetImplAs<Context9>(context), upper.Get(), lower.Get()); 527 } 528 529 angle::Result TextureStorage9_Cube::getBaseTexture(const gl::Context *context, 530 IDirect3DBaseTexture9 **outTexture) 531 { 532 // if the size is not positive this should be treated as an incomplete texture 533 // we handle that here by skipping the d3d texture creation 534 if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) 535 { 536 ASSERT(mMipLevels > 0); 537 ASSERT(mTextureWidth == mTextureHeight); 538 539 IDirect3DDevice9 *device = mRenderer->getDevice(); 540 HRESULT result = device->CreateCubeTexture( 541 static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels), 542 getUsage(), mTextureFormat, getPool(), &mTexture, nullptr); 543 ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create cube storage texture"); 544 } 545 546 *outTexture = mTexture; 547 return angle::Result::Continue; 548 } 549 550 angle::Result TextureStorage9_Cube::copyToStorage(const gl::Context *context, 551 TextureStorage *destStorage) 552 { 553 ASSERT(destStorage); 554 555 TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage); 556 557 int levels = getLevelCount(); 558 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets()) 559 { 560 for (int i = 0; i < levels; i++) 561 { 562 angle::ComPtr<IDirect3DSurface9> srcSurf = nullptr; 563 ANGLE_TRY(getSurfaceLevel(context, face, i, false, &srcSurf)); 564 565 angle::ComPtr<IDirect3DSurface9> dstSurf = nullptr; 566 ANGLE_TRY(dest9->getSurfaceLevel(context, face, i, true, &dstSurf)); 567 568 ANGLE_TRY( 569 mRenderer->copyToRenderTarget(context, dstSurf.Get(), srcSurf.Get(), isManaged())); 570 } 571 } 572 573 return angle::Result::Continue; 574 } 575 } // namespace rx