blob: df9965b48b82d39911e07ff365bba3427f02773d [file] [log] [blame]
daniel@transgaming.coma8aac672012-12-20 21:08:00 +00001//
2// Copyright (c) 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// Image11.h: Implements the rx::Image11 class, which acts as the interface to
8// the actual underlying resources of a Texture
9
10#include "libGLESv2/renderer/Renderer11.h"
11#include "libGLESv2/renderer/Image11.h"
daniel@transgaming.com46cf2492013-01-11 04:06:43 +000012#include "libGLESv2/renderer/TextureStorage11.h"
shannon.woods@transgaming.comc8cd7f62013-01-25 21:52:40 +000013#include "libGLESv2/Framebuffer.h"
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000014
15#include "libGLESv2/main.h"
16#include "libGLESv2/mathutil.h"
17#include "libGLESv2/renderer/renderer11_utils.h"
shannon.woods@transgaming.com2b132f42013-01-25 21:52:47 +000018#include "libGLESv2/renderer/generatemip.h"
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000019
20namespace rx
21{
22
23Image11::Image11()
24{
25 mStagingTexture = NULL;
26 mRenderer = NULL;
27 mDXGIFormat = DXGI_FORMAT_UNKNOWN;
28}
29
30Image11::~Image11()
31{
32 if (mStagingTexture)
33 {
34 mStagingTexture->Release();
35 }
36}
37
38Image11 *Image11::makeImage11(Image *img)
39{
apatrick@chromium.org8b400b12013-01-30 21:53:40 +000040 ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000041 return static_cast<rx::Image11*>(img);
42}
43
shannon.woods@transgaming.com2b132f42013-01-25 21:52:47 +000044void Image11::generateMipmap(Image11 *dest, Image11 *src)
45{
46 ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
47 ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
48 ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
49
50 D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
51 dest->map(&destMapped);
52 src->map(&srcMapped);
53
54 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
55 unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
56
57 if (sourceData && destData)
58 {
59 switch (src->getDXGIFormat())
60 {
61 case DXGI_FORMAT_R8G8B8A8_UNORM:
62 case DXGI_FORMAT_B8G8R8A8_UNORM:
63 GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
64 break;
65 case DXGI_FORMAT_A8_UNORM:
66 GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
67 break;
68 case DXGI_FORMAT_R8_UNORM:
69 GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
70 break;
71 case DXGI_FORMAT_R32G32B32A32_FLOAT:
72 GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
73 break;
74 case DXGI_FORMAT_R32G32B32_FLOAT:
75 GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
76 break;
77 case DXGI_FORMAT_R16G16B16A16_FLOAT:
78 GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
79 break;
80 case DXGI_FORMAT_R8G8_UNORM:
81 GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
82 break;
83 case DXGI_FORMAT_R16_FLOAT:
84 GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
85 break;
86 case DXGI_FORMAT_R16G16_FLOAT:
87 GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
88 break;
89 case DXGI_FORMAT_R32_FLOAT:
90 GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
91 break;
92 case DXGI_FORMAT_R32G32_FLOAT:
93 GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
94 break;
95 default:
96 UNREACHABLE();
97 break;
98 }
99
100 dest->unmap();
101 src->unmap();
102 }
103
104 dest->markDirty();
105}
106
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000107bool Image11::isDirty() const
108{
109 return (mStagingTexture && mDirty);
110}
111
daniel@transgaming.com5ea16ef2013-01-11 04:06:30 +0000112ID3D11Texture2D *Image11::getStagingTexture()
113{
114 createStagingTexture();
115
116 return mStagingTexture;
117}
118
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000119bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000120{
daniel@transgaming.com46cf2492013-01-11 04:06:43 +0000121 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
122 return storage11->updateSubresourceLevel(getStagingTexture(), level, 0, xoffset, yoffset, width, height);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000123}
124
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000125bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000126{
daniel@transgaming.com46cf2492013-01-11 04:06:43 +0000127 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
128 return storage11->updateSubresourceLevel(getStagingTexture(), level, face, xoffset, yoffset, width, height);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000129}
130
131bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
132{
133 if (mWidth != width ||
134 mHeight != height ||
135 mInternalFormat != internalformat ||
136 forceRelease)
137 {
138 mRenderer = Renderer11::makeRenderer11(renderer);
139
140 mWidth = width;
141 mHeight = height;
142 mInternalFormat = internalformat;
143 // compute the d3d format that will be used
144 mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
145 mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
146
147 if (mStagingTexture)
148 {
149 mStagingTexture->Release();
150 mStagingTexture = NULL;
151 }
152
153 return true;
154 }
155
156 return false;
157}
158
159bool Image11::isRenderableFormat() const
160{
shannon.woods@transgaming.com2a0a39e2013-01-25 21:50:15 +0000161 return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000162}
163
164DXGI_FORMAT Image11::getDXGIFormat() const
165{
166 // this should only happen if the image hasn't been redefined first
167 // which would be a bug by the caller
168 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
169
170 return mDXGIFormat;
171}
172
173// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
174// into the target pixel rectangle.
175void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
176 GLint unpackAlignment, const void *input)
177{
178 D3D11_MAPPED_SUBRESOURCE mappedImage;
179 HRESULT result = map(&mappedImage);
180 if (FAILED(result))
181 {
182 ERR("Could not map image for loading.");
183 return;
184 }
185
186 GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
187 size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
188 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
189
190 switch (mInternalFormat)
191 {
192 case GL_ALPHA8_EXT:
daniel@transgaming.com26041c92013-01-11 04:08:58 +0000193 loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000194 break;
195 case GL_LUMINANCE8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000196 loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000197 break;
198 case GL_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000199 loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000200 break;
201 case GL_LUMINANCE32F_EXT:
daniel@transgaming.com26041c92013-01-11 04:08:58 +0000202 loadLuminanceFloatDataToRGB(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000203 break;
204 case GL_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000205 loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000206 break;
207 case GL_LUMINANCE16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000208 loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000209 break;
210 case GL_LUMINANCE8_ALPHA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000211 loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000212 break;
213 case GL_LUMINANCE_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000214 loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000215 break;
216 case GL_LUMINANCE_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000217 loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000218 break;
219 case GL_RGB8_OES:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000220 loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000221 break;
222 case GL_RGB565:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000223 loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000224 break;
225 case GL_RGBA8_OES:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000226 loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000227 break;
228 case GL_RGBA4:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000229 loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000230 break;
231 case GL_RGB5_A1:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000232 loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000233 break;
234 case GL_BGRA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000235 loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000236 break;
237 case GL_RGB32F_EXT:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000238 loadRGBFloatDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000239 break;
240 case GL_RGB16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000241 loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000242 break;
243 case GL_RGBA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000244 loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000245 break;
246 case GL_RGBA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000247 loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000248 break;
249 default: UNREACHABLE();
250 }
251
252 unmap();
253}
254
255void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
256 const void *input)
257{
258 ASSERT(xoffset % 4 == 0);
259 ASSERT(yoffset % 4 == 0);
260
261 D3D11_MAPPED_SUBRESOURCE mappedImage;
262 HRESULT result = map(&mappedImage);
263 if (FAILED(result))
264 {
265 ERR("Could not map image for loading.");
266 return;
267 }
268
269 // Size computation assumes a 4x4 block compressed texture format
270 size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
271 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
272
273 GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
274 GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
275 int rows = inputSize / inputPitch;
276 for (int i = 0; i < rows; ++i)
277 {
278 memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
279 }
280
281 unmap();
282}
283
284void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
285{
shannon.woods@transgaming.comc8cd7f62013-01-25 21:52:40 +0000286 if (source->getColorbuffer() && source->getColorbuffer()->getInternalFormat() == (GLuint)mInternalFormat)
287 {
288 // No conversion needed-- use copyback fastpath
289 ID3D11Texture2D *colorBufferTexture = NULL;
290 unsigned int subresourceIndex = 0;
291
292 if (mRenderer->getRenderTargetResource(source, &subresourceIndex, &colorBufferTexture))
293 {
294 D3D11_TEXTURE2D_DESC textureDesc;
295 colorBufferTexture->GetDesc(&textureDesc);
296
297 ID3D11Device *device = mRenderer->getDevice();
298 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
299
300 ID3D11Texture2D* srcTex = NULL;
301 if (textureDesc.SampleDesc.Count > 1)
302 {
303 D3D11_TEXTURE2D_DESC resolveDesc;
304 resolveDesc.Width = textureDesc.Width;
305 resolveDesc.Height = textureDesc.Height;
306 resolveDesc.MipLevels = 1;
307 resolveDesc.ArraySize = 1;
308 resolveDesc.Format = textureDesc.Format;
309 resolveDesc.SampleDesc.Count = 1;
310 resolveDesc.SampleDesc.Quality = 0;
311 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
312 resolveDesc.BindFlags = 0;
313 resolveDesc.CPUAccessFlags = 0;
314 resolveDesc.MiscFlags = 0;
315
316 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
317 if (FAILED(result))
318 {
319 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
320 return;
321 }
322
323 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
324 subresourceIndex = 0;
325 }
326 else
327 {
328 srcTex = colorBufferTexture;
329 srcTex->AddRef();
330 }
331
332 D3D11_BOX srcBox;
333 srcBox.left = x;
334 srcBox.right = x + width;
335 srcBox.top = y;
336 srcBox.bottom = y + height;
337 srcBox.front = 0;
338 srcBox.back = 1;
339
340 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
341
342 srcTex->Release();
343 colorBufferTexture->Release();
344 }
345 }
346 else
347 {
348 // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
349 D3D11_MAPPED_SUBRESOURCE mappedImage;
350 HRESULT result = map(&mappedImage);
351
352 mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat),
353 gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, mappedImage.pData);
354
355 unmap();
356 }
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000357}
358
359void Image11::createStagingTexture()
360{
361 if (mStagingTexture)
362 {
363 return;
364 }
365
366 ID3D11Texture2D *newTexture = NULL;
367 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
shannon.woods@transgaming.comeec5c632013-02-28 23:04:21 +0000368 ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000369
370 if (mWidth != 0 && mHeight != 0)
371 {
372 ID3D11Device *device = mRenderer->getDevice();
373
374 D3D11_TEXTURE2D_DESC desc;
375 desc.Width = mWidth;
376 desc.Height = mHeight;
377 desc.MipLevels = desc.ArraySize = 1;
378 desc.Format = dxgiFormat;
379 desc.SampleDesc.Count = 1;
380 desc.SampleDesc.Quality = 0;
381 desc.Usage = D3D11_USAGE_STAGING;
382 desc.BindFlags = 0;
383 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
384 desc.MiscFlags = 0;
385
386 HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
387
388 if (FAILED(result))
389 {
390 ASSERT(result == E_OUTOFMEMORY);
391 ERR("Creating image failed.");
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000392 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000393 }
394 }
395
396 mStagingTexture = newTexture;
397 mDirty = false;
398}
399
400HRESULT Image11::map(D3D11_MAPPED_SUBRESOURCE *map)
401{
402 createStagingTexture();
403
shannon.woods@transgaming.comddd6c802013-02-28 23:05:14 +0000404 HRESULT result = E_FAIL;
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000405
406 if (mStagingTexture)
407 {
408 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
409 result = deviceContext->Map(mStagingTexture, 0, D3D11_MAP_WRITE, 0, map);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000410
shannon.woods@transgaming.comddd6c802013-02-28 23:05:14 +0000411 // this can fail if the device is removed (from TDR)
412 if (d3d11::isDeviceLostError(result))
413 {
414 mRenderer->notifyDeviceLost();
415 }
416 else if (SUCCEEDED(result))
417 {
418 mDirty = true;
419 }
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000420 }
421
422 return result;
423}
424
425void Image11::unmap()
426{
427 if (mStagingTexture)
428 {
429 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
430 deviceContext->Unmap(mStagingTexture, 0);
431 }
432}
433
434}