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/Renderer11.h" 12 #include "libGLESv2/renderer/Image11.h" 13 #include "libGLESv2/renderer/TextureStorage11.h" 14 #include "libGLESv2/Framebuffer.h" 15 #include "libGLESv2/Renderbuffer.h" 16 17 #include "libGLESv2/main.h" 18 #include "libGLESv2/utilities.h" 19 #include "libGLESv2/renderer/renderer11_utils.h" 20 #include "libGLESv2/renderer/generatemip.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 if (mStagingTexture) 35 { 36 mStagingTexture->Release(); 37 } 38 } 39 40 Image11 *Image11::makeImage11(Image *img) 41 { 42 ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); 43 return static_cast<rx::Image11*>(img); 44 } 45 46 void Image11::generateMipmap(Image11 *dest, Image11 *src) 47 { 48 ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); 49 ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); 50 ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); 51 52 D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped; 53 dest->map(D3D11_MAP_WRITE, &destMapped); 54 src->map(D3D11_MAP_READ, &srcMapped); 55 56 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData); 57 unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData); 58 59 if (sourceData && destData) 60 { 61 switch (src->getDXGIFormat()) 62 { 63 case DXGI_FORMAT_R8G8B8A8_UNORM: 64 case DXGI_FORMAT_B8G8R8A8_UNORM: 65 GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 66 break; 67 case DXGI_FORMAT_A8_UNORM: 68 GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 69 break; 70 case DXGI_FORMAT_R8_UNORM: 71 GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 72 break; 73 case DXGI_FORMAT_R32G32B32A32_FLOAT: 74 GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 75 break; 76 case DXGI_FORMAT_R32G32B32_FLOAT: 77 GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 78 break; 79 case DXGI_FORMAT_R16G16B16A16_FLOAT: 80 GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 81 break; 82 case DXGI_FORMAT_R8G8_UNORM: 83 GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 84 break; 85 case DXGI_FORMAT_R16_FLOAT: 86 GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 87 break; 88 case DXGI_FORMAT_R16G16_FLOAT: 89 GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 90 break; 91 case DXGI_FORMAT_R32_FLOAT: 92 GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 93 break; 94 case DXGI_FORMAT_R32G32_FLOAT: 95 GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch); 96 break; 97 default: 98 UNREACHABLE(); 99 break; 100 } 101 102 dest->unmap(); 103 src->unmap(); 104 } 105 106 dest->markDirty(); 107 } 108 109 bool Image11::isDirty() const 110 { 111 return (mStagingTexture && mDirty); 112 } 113 114 bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 115 { 116 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); 117 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height); 118 } 119 120 bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 121 { 122 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); 123 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height); 124 } 125 126 bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) 127 { 128 if (mWidth != width || 129 mHeight != height || 130 mInternalFormat != internalformat || 131 forceRelease) 132 { 133 mRenderer = Renderer11::makeRenderer11(renderer); 134 135 mWidth = width; 136 mHeight = height; 137 mInternalFormat = internalformat; 138 // compute the d3d format that will be used 139 mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat); 140 mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat); 141 142 if (mStagingTexture) 143 { 144 mStagingTexture->Release(); 145 mStagingTexture = NULL; 146 } 147 148 return true; 149 } 150 151 return false; 152 } 153 154 bool Image11::isRenderableFormat() const 155 { 156 return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat); 157 } 158 159 DXGI_FORMAT Image11::getDXGIFormat() const 160 { 161 // this should only happen if the image hasn't been redefined first 162 // which would be a bug by the caller 163 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); 164 165 return mDXGIFormat; 166 } 167 168 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input 169 // into the target pixel rectangle. 170 void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 171 GLint unpackAlignment, const void *input) 172 { 173 D3D11_MAPPED_SUBRESOURCE mappedImage; 174 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 175 if (FAILED(result)) 176 { 177 ERR("Could not map image for loading."); 178 return; 179 } 180 181 GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment); 182 size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8; 183 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize)); 184 185 switch (mInternalFormat) 186 { 187 case GL_ALPHA8_EXT: 188 loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 189 break; 190 case GL_LUMINANCE8_EXT: 191 loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false); 192 break; 193 case GL_ALPHA32F_EXT: 194 loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 195 break; 196 case GL_LUMINANCE32F_EXT: 197 loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 198 break; 199 case GL_ALPHA16F_EXT: 200 loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 201 break; 202 case GL_LUMINANCE16F_EXT: 203 loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 204 break; 205 case GL_LUMINANCE8_ALPHA8_EXT: 206 loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false); 207 break; 208 case GL_LUMINANCE_ALPHA32F_EXT: 209 loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 210 break; 211 case GL_LUMINANCE_ALPHA16F_EXT: 212 loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 213 break; 214 case GL_RGB8_OES: 215 loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 216 break; 217 case GL_RGB565: 218 loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 219 break; 220 case GL_RGBA8_OES: 221 loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 222 break; 223 case GL_RGBA4: 224 loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 225 break; 226 case GL_RGB5_A1: 227 loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 228 break; 229 case GL_BGRA8_EXT: 230 loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 231 break; 232 case GL_RGB32F_EXT: 233 loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 234 break; 235 case GL_RGB16F_EXT: 236 loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 237 break; 238 case GL_RGBA32F_EXT: 239 loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 240 break; 241 case GL_RGBA16F_EXT: 242 loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData); 243 break; 244 default: UNREACHABLE(); 245 } 246 247 unmap(); 248 } 249 250 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, 251 const void *input) 252 { 253 ASSERT(xoffset % 4 == 0); 254 ASSERT(yoffset % 4 == 0); 255 256 D3D11_MAPPED_SUBRESOURCE mappedImage; 257 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 258 if (FAILED(result)) 259 { 260 ERR("Could not map image for loading."); 261 return; 262 } 263 264 // Size computation assumes a 4x4 block compressed texture format 265 size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8; 266 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize)); 267 268 GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat); 269 GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat); 270 int rows = inputSize / inputPitch; 271 for (int i = 0; i < rows; ++i) 272 { 273 memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch); 274 } 275 276 unmap(); 277 } 278 279 void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 280 { 281 gl::Renderbuffer *colorbuffer = source->getReadColorbuffer(); 282 283 if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat) 284 { 285 // No conversion needed-- use copyback fastpath 286 ID3D11Texture2D *colorBufferTexture = NULL; 287 unsigned int subresourceIndex = 0; 288 289 if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) 290 { 291 D3D11_TEXTURE2D_DESC textureDesc; 292 colorBufferTexture->GetDesc(&textureDesc); 293 294 ID3D11Device *device = mRenderer->getDevice(); 295 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 296 297 ID3D11Texture2D* srcTex = NULL; 298 if (textureDesc.SampleDesc.Count > 1) 299 { 300 D3D11_TEXTURE2D_DESC resolveDesc; 301 resolveDesc.Width = textureDesc.Width; 302 resolveDesc.Height = textureDesc.Height; 303 resolveDesc.MipLevels = 1; 304 resolveDesc.ArraySize = 1; 305 resolveDesc.Format = textureDesc.Format; 306 resolveDesc.SampleDesc.Count = 1; 307 resolveDesc.SampleDesc.Quality = 0; 308 resolveDesc.Usage = D3D11_USAGE_DEFAULT; 309 resolveDesc.BindFlags = 0; 310 resolveDesc.CPUAccessFlags = 0; 311 resolveDesc.MiscFlags = 0; 312 313 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); 314 if (FAILED(result)) 315 { 316 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); 317 return; 318 } 319 320 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); 321 subresourceIndex = 0; 322 } 323 else 324 { 325 srcTex = colorBufferTexture; 326 srcTex->AddRef(); 327 } 328 329 D3D11_BOX srcBox; 330 srcBox.left = x; 331 srcBox.right = x + width; 332 srcBox.top = y; 333 srcBox.bottom = y + height; 334 srcBox.front = 0; 335 srcBox.back = 1; 336 337 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox); 338 339 srcTex->Release(); 340 colorBufferTexture->Release(); 341 } 342 } 343 else 344 { 345 // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels 346 D3D11_MAPPED_SUBRESOURCE mappedImage; 347 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); 348 349 // determine the offset coordinate into the destination buffer 350 GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset; 351 void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset; 352 353 mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat), 354 gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset); 355 356 unmap(); 357 } 358 } 359 360 ID3D11Texture2D *Image11::getStagingTexture() 361 { 362 createStagingTexture(); 363 364 return mStagingTexture; 365 } 366 367 unsigned int Image11::getStagingSubresource() 368 { 369 createStagingTexture(); 370 371 return mStagingSubresource; 372 } 373 374 void Image11::createStagingTexture() 375 { 376 if (mStagingTexture) 377 { 378 return; 379 } 380 381 ID3D11Texture2D *newTexture = NULL; 382 int lodOffset = 1; 383 const DXGI_FORMAT dxgiFormat = getDXGIFormat(); 384 ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures 385 386 if (mWidth != 0 && mHeight != 0) 387 { 388 GLsizei width = mWidth; 389 GLsizei height = mHeight; 390 391 // adjust size if needed for compressed textures 392 gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset); 393 ID3D11Device *device = mRenderer->getDevice(); 394 395 D3D11_TEXTURE2D_DESC desc; 396 desc.Width = width; 397 desc.Height = height; 398 desc.MipLevels = lodOffset + 1; 399 desc.ArraySize = 1; 400 desc.Format = dxgiFormat; 401 desc.SampleDesc.Count = 1; 402 desc.SampleDesc.Quality = 0; 403 desc.Usage = D3D11_USAGE_STAGING; 404 desc.BindFlags = 0; 405 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 406 desc.MiscFlags = 0; 407 408 HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture); 409 410 if (FAILED(result)) 411 { 412 ASSERT(result == E_OUTOFMEMORY); 413 ERR("Creating image failed."); 414 return gl::error(GL_OUT_OF_MEMORY); 415 } 416 } 417 418 mStagingTexture = newTexture; 419 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); 420 mDirty = false; 421 } 422 423 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) 424 { 425 createStagingTexture(); 426 427 HRESULT result = E_FAIL; 428 429 if (mStagingTexture) 430 { 431 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 432 result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); 433 434 // this can fail if the device is removed (from TDR) 435 if (d3d11::isDeviceLostError(result)) 436 { 437 mRenderer->notifyDeviceLost(); 438 } 439 else if (SUCCEEDED(result)) 440 { 441 mDirty = true; 442 } 443 } 444 445 return result; 446 } 447 448 void Image11::unmap() 449 { 450 if (mStagingTexture) 451 { 452 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 453 deviceContext->Unmap(mStagingTexture, mStagingSubresource); 454 } 455 } 456 457 } 458