1 #include "precompiled.h"
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.
8 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
9 // the actual underlying resources of a Texture
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"
17 #include "libGLESv2/main.h"
18 #include "libGLESv2/utilities.h"
19 #include "libGLESv2/renderer/d3d11/renderer11_utils.h"
20 #include "libGLESv2/renderer/generatemip.h"
27 mStagingTexture = NULL;
29 mDXGIFormat = DXGI_FORMAT_UNKNOWN;
36 mStagingTexture->Release();
40 Image11 *Image11::makeImage11(Image *img)
42 ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
43 return static_cast<rx::Image11*>(img);
46 void Image11::generateMipmap(Image11 *dest, Image11 *src)
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());
52 D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
53 dest->map(D3D11_MAP_WRITE, &destMapped);
54 src->map(D3D11_MAP_READ, &srcMapped);
56 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
57 unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
59 if (sourceData && destData)
61 switch (src->getDXGIFormat())
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);
67 case DXGI_FORMAT_A8_UNORM:
68 GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
70 case DXGI_FORMAT_R8_UNORM:
71 GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
73 case DXGI_FORMAT_R32G32B32A32_FLOAT:
74 GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
76 case DXGI_FORMAT_R32G32B32_FLOAT:
77 GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
79 case DXGI_FORMAT_R16G16B16A16_FLOAT:
80 GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
82 case DXGI_FORMAT_R8G8_UNORM:
83 GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
85 case DXGI_FORMAT_R16_FLOAT:
86 GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
88 case DXGI_FORMAT_R16G16_FLOAT:
89 GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
91 case DXGI_FORMAT_R32_FLOAT:
92 GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
94 case DXGI_FORMAT_R32G32_FLOAT:
95 GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
109 static bool FormatRequiresInitialization(DXGI_FORMAT dxgiFormat, GLenum internalFormat)
111 return (dxgiFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(internalFormat) == 0) ||
112 (dxgiFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(internalFormat) == 0);
115 bool Image11::isDirty() const
117 return ((mStagingTexture || FormatRequiresInitialization(mDXGIFormat, mInternalFormat)) && mDirty);
120 bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
122 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
123 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height);
126 bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
128 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
129 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height);
132 bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
134 if (mWidth != width ||
136 mInternalFormat != internalformat ||
139 mRenderer = Renderer11::makeRenderer11(renderer);
143 mInternalFormat = internalformat;
144 // compute the d3d format that will be used
145 mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
146 mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
150 mStagingTexture->Release();
151 mStagingTexture = NULL;
160 bool Image11::isRenderableFormat() const
162 return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
165 DXGI_FORMAT Image11::getDXGIFormat() const
167 // this should only happen if the image hasn't been redefined first
168 // which would be a bug by the caller
169 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
174 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
175 // into the target pixel rectangle.
176 void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
177 GLint unpackAlignment, const void *input)
179 D3D11_MAPPED_SUBRESOURCE mappedImage;
180 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
183 ERR("Could not map image for loading.");
187 GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
188 size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
189 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
191 switch (mInternalFormat)
194 loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
196 case GL_LUMINANCE8_EXT:
197 loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
199 case GL_ALPHA32F_EXT:
200 loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
202 case GL_LUMINANCE32F_EXT:
203 loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
205 case GL_ALPHA16F_EXT:
206 loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
208 case GL_LUMINANCE16F_EXT:
209 loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
211 case GL_LUMINANCE8_ALPHA8_EXT:
212 loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
214 case GL_LUMINANCE_ALPHA32F_EXT:
215 loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
217 case GL_LUMINANCE_ALPHA16F_EXT:
218 loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
221 loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
224 loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
227 loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
230 loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
233 loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
236 loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
239 loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
242 loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
245 loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
248 loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
250 default: UNREACHABLE();
256 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
259 ASSERT(xoffset % 4 == 0);
260 ASSERT(yoffset % 4 == 0);
262 D3D11_MAPPED_SUBRESOURCE mappedImage;
263 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
266 ERR("Could not map image for loading.");
270 // Size computation assumes a 4x4 block compressed texture format
271 size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
272 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
274 GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
275 GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
276 int rows = inputSize / inputPitch;
277 for (int i = 0; i < rows; ++i)
279 memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
285 void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
287 gl::Renderbuffer *colorbuffer = source->getReadColorbuffer();
289 if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat)
291 // No conversion needed-- use copyback fastpath
292 ID3D11Texture2D *colorBufferTexture = NULL;
293 unsigned int subresourceIndex = 0;
295 if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
297 D3D11_TEXTURE2D_DESC textureDesc;
298 colorBufferTexture->GetDesc(&textureDesc);
300 ID3D11Device *device = mRenderer->getDevice();
301 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
303 ID3D11Texture2D* srcTex = NULL;
304 if (textureDesc.SampleDesc.Count > 1)
306 D3D11_TEXTURE2D_DESC resolveDesc;
307 resolveDesc.Width = textureDesc.Width;
308 resolveDesc.Height = textureDesc.Height;
309 resolveDesc.MipLevels = 1;
310 resolveDesc.ArraySize = 1;
311 resolveDesc.Format = textureDesc.Format;
312 resolveDesc.SampleDesc.Count = 1;
313 resolveDesc.SampleDesc.Quality = 0;
314 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
315 resolveDesc.BindFlags = 0;
316 resolveDesc.CPUAccessFlags = 0;
317 resolveDesc.MiscFlags = 0;
319 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
322 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
326 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
327 subresourceIndex = 0;
331 srcTex = colorBufferTexture;
337 srcBox.right = x + width;
339 srcBox.bottom = y + height;
343 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
346 colorBufferTexture->Release();
351 // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
352 D3D11_MAPPED_SUBRESOURCE mappedImage;
353 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
355 // determine the offset coordinate into the destination buffer
356 GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset;
357 void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset;
359 mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat),
360 gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset);
366 ID3D11Texture2D *Image11::getStagingTexture()
368 createStagingTexture();
370 return mStagingTexture;
373 unsigned int Image11::getStagingSubresource()
375 createStagingTexture();
377 return mStagingSubresource;
380 template <typename T, size_t N>
381 static void setDefaultData(ID3D11DeviceContext *deviceContext, ID3D11Texture2D *texture, UINT subresource,
382 GLsizei width, GLsizei height, const T (&defaultData)[N])
384 D3D11_MAPPED_SUBRESOURCE map;
385 deviceContext->Map(texture, subresource, D3D11_MAP_WRITE, 0, &map);
387 unsigned char* ptr = reinterpret_cast<unsigned char*>(map.pData);
388 size_t pixelSize = sizeof(T) * N;
390 for (GLsizei y = 0; y < height; y++)
392 for (GLsizei x = 0; x < width; x++)
394 memcpy(ptr + (y * map.RowPitch) + (x * pixelSize), defaultData, pixelSize);
398 deviceContext->Unmap(texture, subresource);
401 void Image11::createStagingTexture()
408 ID3D11Texture2D *newTexture = NULL;
410 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
411 ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
413 if (mWidth != 0 && mHeight != 0)
415 GLsizei width = mWidth;
416 GLsizei height = mHeight;
418 // adjust size if needed for compressed textures
419 gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset);
420 ID3D11Device *device = mRenderer->getDevice();
422 D3D11_TEXTURE2D_DESC desc;
424 desc.Height = height;
425 desc.MipLevels = lodOffset + 1;
427 desc.Format = dxgiFormat;
428 desc.SampleDesc.Count = 1;
429 desc.SampleDesc.Quality = 0;
430 desc.Usage = D3D11_USAGE_STAGING;
432 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
435 HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
439 ASSERT(result == E_OUTOFMEMORY);
440 ERR("Creating image failed.");
441 return gl::error(GL_OUT_OF_MEMORY);
445 mStagingTexture = newTexture;
446 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
449 if (mDXGIFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(mInternalFormat) == 0)
451 unsigned char defaultPixel[4] = { 0, 0, 0, 255 };
452 setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel);
454 else if (mDXGIFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(mInternalFormat) == 0)
456 float defaultPixel[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
457 setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel);
461 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
463 createStagingTexture();
465 HRESULT result = E_FAIL;
469 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
470 result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
472 // this can fail if the device is removed (from TDR)
473 if (d3d11::isDeviceLostError(result))
475 mRenderer->notifyDeviceLost();
477 else if (SUCCEEDED(result))
486 void Image11::unmap()
490 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
491 deviceContext->Unmap(mStagingTexture, mStagingSubresource);