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 "common/utilities.h"
19 #include "libGLESv2/renderer/d3d11/formatutils11.h"
20 #include "libGLESv2/renderer/d3d11/renderer11_utils.h"
27 mStagingTexture = NULL;
29 mDXGIFormat = DXGI_FORMAT_UNKNOWN;
34 SafeRelease(mStagingTexture);
37 Image11 *Image11::makeImage11(Image *img)
39 ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
40 return static_cast<rx::Image11*>(img);
43 void Image11::generateMipmap(GLuint clientVersion, Image11 *dest, Image11 *src)
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());
49 MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat());
50 ASSERT(mipFunction != NULL);
52 D3D11_MAPPED_SUBRESOURCE destMapped;
53 HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped);
54 if (FAILED(destMapResult))
56 ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult);
60 D3D11_MAPPED_SUBRESOURCE srcMapped;
61 HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped);
62 if (FAILED(srcMapResult))
64 ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult);
70 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
71 unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
73 mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch,
74 destData, destMapped.RowPitch, destMapped.DepthPitch);
82 bool Image11::isDirty() const
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)));
89 bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
91 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
92 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1);
95 bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
97 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
98 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1);
101 bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
103 TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance());
104 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth);
107 bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
109 TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance());
110 return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1);
113 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
115 if (mWidth != width ||
117 mInternalFormat != internalformat ||
120 mRenderer = Renderer11::makeRenderer11(renderer);
121 GLuint clientVersion = mRenderer->getCurrentClientVersion();
126 mInternalFormat = internalformat;
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;
134 SafeRelease(mStagingTexture);
135 mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat);
143 DXGI_FORMAT Image11::getDXGIFormat() const
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);
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)
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);
162 LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type, clientVersion);
163 ASSERT(loadFunction != NULL);
165 D3D11_MAPPED_SUBRESOURCE mappedImage;
166 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
169 ERR("Could not map image for loading.");
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);
179 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
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);
186 GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
187 GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat);
188 GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat);
190 ASSERT(xoffset % outputBlockWidth == 0);
191 ASSERT(yoffset % outputBlockHeight == 0);
193 LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion);
194 ASSERT(loadFunction != NULL);
196 D3D11_MAPPED_SUBRESOURCE mappedImage;
197 HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
200 ERR("Could not map image for loading.");
204 void* offsetMappedData = (void*)((BYTE*)mappedImage.pData + ((yoffset / outputBlockHeight) * mappedImage.RowPitch +
205 (xoffset / outputBlockWidth) * outputPixelSize +
206 zoffset * mappedImage.DepthPitch));
208 loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch,
209 offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
214 void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
216 gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
218 if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat)
220 // No conversion needed-- use copyback fastpath
221 ID3D11Texture2D *colorBufferTexture = NULL;
222 unsigned int subresourceIndex = 0;
224 if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
226 D3D11_TEXTURE2D_DESC textureDesc;
227 colorBufferTexture->GetDesc(&textureDesc);
229 ID3D11Device *device = mRenderer->getDevice();
230 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
232 ID3D11Texture2D* srcTex = NULL;
233 if (textureDesc.SampleDesc.Count > 1)
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;
248 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
251 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
255 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
256 subresourceIndex = 0;
260 srcTex = colorBufferTexture;
266 srcBox.right = x + width;
268 srcBox.bottom = y + height;
272 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
275 SafeRelease(colorBufferTexture);
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);
285 ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
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;
294 GLenum format = gl::GetFormat(mInternalFormat, clientVersion);
295 GLenum type = gl::GetType(mInternalFormat, clientVersion);
297 mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
303 ID3D11Resource *Image11::getStagingTexture()
305 createStagingTexture();
307 return mStagingTexture;
310 unsigned int Image11::getStagingSubresource()
312 createStagingTexture();
314 return mStagingSubresource;
317 void Image11::createStagingTexture()
324 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
326 if (mWidth > 0 && mHeight > 0 && mDepth > 0)
328 ID3D11Device *device = mRenderer->getDevice();
332 GLsizei width = mWidth;
333 GLsizei height = mHeight;
335 // adjust size if needed for compressed textures
336 d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
338 if (mTarget == GL_TEXTURE_3D)
340 ID3D11Texture3D *newTexture = NULL;
342 D3D11_TEXTURE3D_DESC desc;
344 desc.Height = height;
346 desc.MipLevels = lodOffset + 1;
347 desc.Format = dxgiFormat;
348 desc.Usage = D3D11_USAGE_STAGING;
350 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
353 if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
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);
360 result = device->CreateTexture3D(&desc, initialData.data(), &newTexture);
364 result = device->CreateTexture3D(&desc, NULL, &newTexture);
369 ASSERT(result == E_OUTOFMEMORY);
370 ERR("Creating image failed.");
371 return gl::error(GL_OUT_OF_MEMORY);
374 mStagingTexture = newTexture;
375 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
377 else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP)
379 ID3D11Texture2D *newTexture = NULL;
381 D3D11_TEXTURE2D_DESC desc;
383 desc.Height = height;
384 desc.MipLevels = lodOffset + 1;
386 desc.Format = dxgiFormat;
387 desc.SampleDesc.Count = 1;
388 desc.SampleDesc.Quality = 0;
389 desc.Usage = D3D11_USAGE_STAGING;
391 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
394 if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
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);
401 result = device->CreateTexture2D(&desc, initialData.data(), &newTexture);
405 result = device->CreateTexture2D(&desc, NULL, &newTexture);
410 ASSERT(result == E_OUTOFMEMORY);
411 ERR("Creating image failed.");
412 return gl::error(GL_OUT_OF_MEMORY);
415 mStagingTexture = newTexture;
416 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
427 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
429 createStagingTexture();
431 HRESULT result = E_FAIL;
435 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
436 result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
438 // this can fail if the device is removed (from TDR)
439 if (d3d11::isDeviceLostError(result))
441 mRenderer->notifyDeviceLost();
443 else if (SUCCEEDED(result))
452 void Image11::unmap()
456 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
457 deviceContext->Unmap(mStagingTexture, mStagingSubresource);