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 // Image11.h: Implements the rx::Image11 class, which acts as the interface to 9 // the actual underlying resources of a Texture 10 11 #include "libGLESv2/renderer/d3d11/Renderer11.h" 12 #include "libGLESv2/renderer/d3d11/Image11.h" 13 #include "libGLESv2/renderer/d3d11/TextureStorage11.h" 14 #include "libGLESv2/Framebuffer.h" 15 #include "libGLESv2/Renderbuffer.h" 16 17 #include "libGLESv2/main.h" 18 #include "common/utilities.h" 19 #include "libGLESv2/renderer/d3d11/formatutils11.h" 20 #include "libGLESv2/renderer/d3d11/renderer11_utils.h" 21 22 namespace rx 23 { 24 25 Image11::Image11() 26 { 27 mStagingTexture = NULL; 28 mRenderer = NULL; 29 mDXGIFormat = DXGI_FORMAT_UNKNOWN; 30 } 31 32 Image11::~Image11() 33 { 34 SafeRelease(mStagingTexture); 35 } 36 37 Image11 *Image11::makeImage11(Image *img) 38 { 39 ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); 40 return static_cast<rx::Image11*>(img); 41 } 42 43 void Image11::generateMipmap(GLuint clientVersion, Image11 *dest, Image11 *src) 44 { 45 ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); 46 ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); 47 ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); 48 49 MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat()); 50 ASSERT(mipFunction != NULL); 51 52 D3D11_MAPPED_SUBRESOURCE destMapped; 53 HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped); 54 if (FAILED(destMapResult)) 55 { 56 ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult); 57 return; 58 } 59 60 D3D11_MAPPED_SUBRESOURCE srcMapped; 61 HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped); 62 if (FAILED(srcMapResult)) 63 { 64 ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult); 65 66 dest->unmap(); 67 return; 68 } 69 70 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData); 71 unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData); 72 73 mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, 74 destData, destMapped.RowPitch, destMapped.DepthPitch); 75 76 dest->unmap(); 77 src->unmap(); 78 79 dest->markDirty(); 80 } 81 82 bool Image11::isDirty() const 83 { 84 // Make sure that this image is marked as dirty even if the staging texture hasn't been created yet 85 // if initialization is required before use. 86 return (mDirty && (mStagingTexture || gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))); 87 } 88 89 bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 90 { 91 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); 92 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1); 93 } 94 95 bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 96 { 97 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); 98 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1); 99 } 100 101 bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) 102 { 103 TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance()); 104 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth); 105 } 106 107 bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) 108 { 109 TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance()); 110 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1); 111 } 112 113 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) 114 { 115 if (mWidth != width || 116 mHeight != height || 117 mInternalFormat != internalformat || 118 forceRelease) 119 { 120 mRenderer = Renderer11::makeRenderer11(renderer); 121 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 122 123 mWidth = width; 124 mHeight = height; 125 mDepth = depth; 126 mInternalFormat = internalformat; 127 mTarget = target; 128 129 // compute the d3d format that will be used 130 mDXGIFormat = gl_d3d11::GetTexFormat(internalformat, clientVersion); 131 mActualFormat = d3d11_gl::GetInternalFormat(mDXGIFormat, clientVersion); 132 mRenderable = gl_d3d11::GetRTVFormat(internalformat, clientVersion) != DXGI_FORMAT_UNKNOWN; 133 134 SafeRelease(mStagingTexture); 135 mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat); 136 137 return true; 138 } 139 140 return false; 141 } 142 143 DXGI_FORMAT Image11::getDXGIFormat() const 144 { 145 // this should only happen if the image hasn't been redefined first 146 // which would be a bug by the caller 147 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); 148 149 return mDXGIFormat; 150 } 151 152 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input 153 // into the target pixel rectangle. 154 void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 155 GLint unpackAlignment, GLenum type, const void *input) 156 { 157 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 158 GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, clientVersion, width, unpackAlignment); 159 GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, clientVersion, width, height, unpackAlignment); 160 GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); 161 162 LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type, clientVersion); 163 ASSERT(loadFunction != NULL); 164 165 D3D11_MAPPED_SUBRESOURCE mappedImage; 166 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 167 if (FAILED(result)) 168 { 169 ERR("Could not map image for loading."); 170 return; 171 } 172 173 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch)); 174 loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); 175 176 unmap(); 177 } 178 179 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 180 const void *input) 181 { 182 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 183 GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, 1); 184 GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, height, 1); 185 186 GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat); 187 GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat); 188 GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat); 189 190 ASSERT(xoffset % outputBlockWidth == 0); 191 ASSERT(yoffset % outputBlockHeight == 0); 192 193 LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion); 194 ASSERT(loadFunction != NULL); 195 196 D3D11_MAPPED_SUBRESOURCE mappedImage; 197 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 198 if (FAILED(result)) 199 { 200 ERR("Could not map image for loading."); 201 return; 202 } 203 204 void* offsetMappedData = (void*)((BYTE*)mappedImage.pData + ((yoffset / outputBlockHeight) * mappedImage.RowPitch + 205 (xoffset / outputBlockWidth) * outputPixelSize + 206 zoffset * mappedImage.DepthPitch)); 207 208 loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch, 209 offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); 210 211 unmap(); 212 } 213 214 void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 215 { 216 gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); 217 218 if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat) 219 { 220 // No conversion needed-- use copyback fastpath 221 ID3D11Texture2D *colorBufferTexture = NULL; 222 unsigned int subresourceIndex = 0; 223 224 if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) 225 { 226 D3D11_TEXTURE2D_DESC textureDesc; 227 colorBufferTexture->GetDesc(&textureDesc); 228 229 ID3D11Device *device = mRenderer->getDevice(); 230 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 231 232 ID3D11Texture2D* srcTex = NULL; 233 if (textureDesc.SampleDesc.Count > 1) 234 { 235 D3D11_TEXTURE2D_DESC resolveDesc; 236 resolveDesc.Width = textureDesc.Width; 237 resolveDesc.Height = textureDesc.Height; 238 resolveDesc.MipLevels = 1; 239 resolveDesc.ArraySize = 1; 240 resolveDesc.Format = textureDesc.Format; 241 resolveDesc.SampleDesc.Count = 1; 242 resolveDesc.SampleDesc.Quality = 0; 243 resolveDesc.Usage = D3D11_USAGE_DEFAULT; 244 resolveDesc.BindFlags = 0; 245 resolveDesc.CPUAccessFlags = 0; 246 resolveDesc.MiscFlags = 0; 247 248 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); 249 if (FAILED(result)) 250 { 251 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); 252 return; 253 } 254 255 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); 256 subresourceIndex = 0; 257 } 258 else 259 { 260 srcTex = colorBufferTexture; 261 srcTex->AddRef(); 262 } 263 264 D3D11_BOX srcBox; 265 srcBox.left = x; 266 srcBox.right = x + width; 267 srcBox.top = y; 268 srcBox.bottom = y + height; 269 srcBox.front = 0; 270 srcBox.back = 1; 271 272 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox); 273 274 SafeRelease(srcTex); 275 SafeRelease(colorBufferTexture); 276 } 277 } 278 else 279 { 280 // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels 281 D3D11_MAPPED_SUBRESOURCE mappedImage; 282 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 283 if (FAILED(result)) 284 { 285 ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result); 286 return; 287 } 288 289 // determine the offset coordinate into the destination buffer 290 GLuint clientVersion = mRenderer->getCurrentClientVersion(); 291 GLsizei rowOffset = gl::GetPixelBytes(mActualFormat, clientVersion) * xoffset; 292 void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; 293 294 GLenum format = gl::GetFormat(mInternalFormat, clientVersion); 295 GLenum type = gl::GetType(mInternalFormat, clientVersion); 296 297 mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); 298 299 unmap(); 300 } 301 } 302 303 ID3D11Resource *Image11::getStagingTexture() 304 { 305 createStagingTexture(); 306 307 return mStagingTexture; 308 } 309 310 unsigned int Image11::getStagingSubresource() 311 { 312 createStagingTexture(); 313 314 return mStagingSubresource; 315 } 316 317 void Image11::createStagingTexture() 318 { 319 if (mStagingTexture) 320 { 321 return; 322 } 323 324 const DXGI_FORMAT dxgiFormat = getDXGIFormat(); 325 326 if (mWidth > 0 && mHeight > 0 && mDepth > 0) 327 { 328 ID3D11Device *device = mRenderer->getDevice(); 329 HRESULT result; 330 331 int lodOffset = 1; 332 GLsizei width = mWidth; 333 GLsizei height = mHeight; 334 335 // adjust size if needed for compressed textures 336 d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); 337 338 if (mTarget == GL_TEXTURE_3D) 339 { 340 ID3D11Texture3D *newTexture = NULL; 341 342 D3D11_TEXTURE3D_DESC desc; 343 desc.Width = width; 344 desc.Height = height; 345 desc.Depth = mDepth; 346 desc.MipLevels = lodOffset + 1; 347 desc.Format = dxgiFormat; 348 desc.Usage = D3D11_USAGE_STAGING; 349 desc.BindFlags = 0; 350 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 351 desc.MiscFlags = 0; 352 353 if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) 354 { 355 std::vector<D3D11_SUBRESOURCE_DATA> initialData; 356 std::vector< std::vector<BYTE> > textureData; 357 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height, 358 mDepth, lodOffset + 1, &initialData, &textureData); 359 360 result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); 361 } 362 else 363 { 364 result = device->CreateTexture3D(&desc, NULL, &newTexture); 365 } 366 367 if (FAILED(result)) 368 { 369 ASSERT(result == E_OUTOFMEMORY); 370 ERR("Creating image failed."); 371 return gl::error(GL_OUT_OF_MEMORY); 372 } 373 374 mStagingTexture = newTexture; 375 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); 376 } 377 else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) 378 { 379 ID3D11Texture2D *newTexture = NULL; 380 381 D3D11_TEXTURE2D_DESC desc; 382 desc.Width = width; 383 desc.Height = height; 384 desc.MipLevels = lodOffset + 1; 385 desc.ArraySize = 1; 386 desc.Format = dxgiFormat; 387 desc.SampleDesc.Count = 1; 388 desc.SampleDesc.Quality = 0; 389 desc.Usage = D3D11_USAGE_STAGING; 390 desc.BindFlags = 0; 391 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 392 desc.MiscFlags = 0; 393 394 if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)) 395 { 396 std::vector<D3D11_SUBRESOURCE_DATA> initialData; 397 std::vector< std::vector<BYTE> > textureData; 398 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height, 399 1, lodOffset + 1, &initialData, &textureData); 400 401 result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); 402 } 403 else 404 { 405 result = device->CreateTexture2D(&desc, NULL, &newTexture); 406 } 407 408 if (FAILED(result)) 409 { 410 ASSERT(result == E_OUTOFMEMORY); 411 ERR("Creating image failed."); 412 return gl::error(GL_OUT_OF_MEMORY); 413 } 414 415 mStagingTexture = newTexture; 416 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); 417 } 418 else 419 { 420 UNREACHABLE(); 421 } 422 } 423 424 mDirty = false; 425 } 426 427 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) 428 { 429 createStagingTexture(); 430 431 HRESULT result = E_FAIL; 432 433 if (mStagingTexture) 434 { 435 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 436 result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); 437 438 // this can fail if the device is removed (from TDR) 439 if (d3d11::isDeviceLostError(result)) 440 { 441 mRenderer->notifyDeviceLost(); 442 } 443 else if (SUCCEEDED(result)) 444 { 445 mDirty = true; 446 } 447 } 448 449 return result; 450 } 451 452 void Image11::unmap() 453 { 454 if (mStagingTexture) 455 { 456 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 457 deviceContext->Unmap(mStagingTexture, mStagingSubresource); 458 } 459 } 460 461 } 462