blob: 92e186c79454891e9f8801fd3991ae08a2831c32 [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"
18
19namespace rx
20{
21
22Image11::Image11()
23{
24 mStagingTexture = NULL;
25 mRenderer = NULL;
26 mDXGIFormat = DXGI_FORMAT_UNKNOWN;
27}
28
29Image11::~Image11()
30{
31 if (mStagingTexture)
32 {
33 mStagingTexture->Release();
34 }
35}
36
37Image11 *Image11::makeImage11(Image *img)
38{
39 ASSERT(dynamic_cast<rx::Image11*>(img) != NULL);
40 return static_cast<rx::Image11*>(img);
41}
42
43bool Image11::isDirty() const
44{
45 return (mStagingTexture && mDirty);
46}
47
daniel@transgaming.com5ea16ef2013-01-11 04:06:30 +000048ID3D11Texture2D *Image11::getStagingTexture()
49{
50 createStagingTexture();
51
52 return mStagingTexture;
53}
54
daniel@transgaming.com87705f82012-12-20 21:10:45 +000055bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000056{
daniel@transgaming.com46cf2492013-01-11 04:06:43 +000057 TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
58 return storage11->updateSubresourceLevel(getStagingTexture(), level, 0, xoffset, yoffset, width, height);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000059}
60
daniel@transgaming.com87705f82012-12-20 21:10:45 +000061bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000062{
daniel@transgaming.com46cf2492013-01-11 04:06:43 +000063 TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
64 return storage11->updateSubresourceLevel(getStagingTexture(), level, face, xoffset, yoffset, width, height);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000065}
66
67bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
68{
69 if (mWidth != width ||
70 mHeight != height ||
71 mInternalFormat != internalformat ||
72 forceRelease)
73 {
74 mRenderer = Renderer11::makeRenderer11(renderer);
75
76 mWidth = width;
77 mHeight = height;
78 mInternalFormat = internalformat;
79 // compute the d3d format that will be used
80 mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
81 mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
82
83 if (mStagingTexture)
84 {
85 mStagingTexture->Release();
86 mStagingTexture = NULL;
87 }
88
89 return true;
90 }
91
92 return false;
93}
94
95bool Image11::isRenderableFormat() const
96{
shannon.woods@transgaming.com2a0a39e2013-01-25 21:50:15 +000097 return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +000098}
99
100DXGI_FORMAT Image11::getDXGIFormat() const
101{
102 // this should only happen if the image hasn't been redefined first
103 // which would be a bug by the caller
104 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
105
106 return mDXGIFormat;
107}
108
109// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
110// into the target pixel rectangle.
111void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
112 GLint unpackAlignment, const void *input)
113{
114 D3D11_MAPPED_SUBRESOURCE mappedImage;
115 HRESULT result = map(&mappedImage);
116 if (FAILED(result))
117 {
118 ERR("Could not map image for loading.");
119 return;
120 }
121
122 GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
123 size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
124 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
125
126 switch (mInternalFormat)
127 {
128 case GL_ALPHA8_EXT:
daniel@transgaming.com26041c92013-01-11 04:08:58 +0000129 loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000130 break;
131 case GL_LUMINANCE8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000132 loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000133 break;
134 case GL_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000135 loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000136 break;
137 case GL_LUMINANCE32F_EXT:
daniel@transgaming.com26041c92013-01-11 04:08:58 +0000138 loadLuminanceFloatDataToRGB(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000139 break;
140 case GL_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000141 loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000142 break;
143 case GL_LUMINANCE16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000144 loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000145 break;
146 case GL_LUMINANCE8_ALPHA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000147 loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000148 break;
149 case GL_LUMINANCE_ALPHA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000150 loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000151 break;
152 case GL_LUMINANCE_ALPHA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000153 loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000154 break;
155 case GL_RGB8_OES:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000156 loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000157 break;
158 case GL_RGB565:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000159 loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000160 break;
161 case GL_RGBA8_OES:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000162 loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000163 break;
164 case GL_RGBA4:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000165 loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000166 break;
167 case GL_RGB5_A1:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000168 loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000169 break;
170 case GL_BGRA8_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000171 loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000172 break;
173 case GL_RGB32F_EXT:
daniel@transgaming.com005979d2012-12-20 21:11:29 +0000174 loadRGBFloatDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000175 break;
176 case GL_RGB16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000177 loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000178 break;
179 case GL_RGBA32F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000180 loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000181 break;
182 case GL_RGBA16F_EXT:
daniel@transgaming.com8ca7d372012-12-20 21:11:22 +0000183 loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000184 break;
185 default: UNREACHABLE();
186 }
187
188 unmap();
189}
190
191void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
192 const void *input)
193{
194 ASSERT(xoffset % 4 == 0);
195 ASSERT(yoffset % 4 == 0);
196
197 D3D11_MAPPED_SUBRESOURCE mappedImage;
198 HRESULT result = map(&mappedImage);
199 if (FAILED(result))
200 {
201 ERR("Could not map image for loading.");
202 return;
203 }
204
205 // Size computation assumes a 4x4 block compressed texture format
206 size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
207 void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
208
209 GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
210 GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
211 int rows = inputSize / inputPitch;
212 for (int i = 0; i < rows; ++i)
213 {
214 memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
215 }
216
217 unmap();
218}
219
220void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
221{
shannon.woods@transgaming.comc8cd7f62013-01-25 21:52:40 +0000222 if (source->getColorbuffer() && source->getColorbuffer()->getInternalFormat() == (GLuint)mInternalFormat)
223 {
224 // No conversion needed-- use copyback fastpath
225 ID3D11Texture2D *colorBufferTexture = NULL;
226 unsigned int subresourceIndex = 0;
227
228 if (mRenderer->getRenderTargetResource(source, &subresourceIndex, &colorBufferTexture))
229 {
230 D3D11_TEXTURE2D_DESC textureDesc;
231 colorBufferTexture->GetDesc(&textureDesc);
232
233 ID3D11Device *device = mRenderer->getDevice();
234 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
235
236 ID3D11Texture2D* srcTex = NULL;
237 if (textureDesc.SampleDesc.Count > 1)
238 {
239 D3D11_TEXTURE2D_DESC resolveDesc;
240 resolveDesc.Width = textureDesc.Width;
241 resolveDesc.Height = textureDesc.Height;
242 resolveDesc.MipLevels = 1;
243 resolveDesc.ArraySize = 1;
244 resolveDesc.Format = textureDesc.Format;
245 resolveDesc.SampleDesc.Count = 1;
246 resolveDesc.SampleDesc.Quality = 0;
247 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
248 resolveDesc.BindFlags = 0;
249 resolveDesc.CPUAccessFlags = 0;
250 resolveDesc.MiscFlags = 0;
251
252 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
253 if (FAILED(result))
254 {
255 ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
256 return;
257 }
258
259 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
260 subresourceIndex = 0;
261 }
262 else
263 {
264 srcTex = colorBufferTexture;
265 srcTex->AddRef();
266 }
267
268 D3D11_BOX srcBox;
269 srcBox.left = x;
270 srcBox.right = x + width;
271 srcBox.top = y;
272 srcBox.bottom = y + height;
273 srcBox.front = 0;
274 srcBox.back = 1;
275
276 deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
277
278 srcTex->Release();
279 colorBufferTexture->Release();
280 }
281 }
282 else
283 {
284 // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
285 D3D11_MAPPED_SUBRESOURCE mappedImage;
286 HRESULT result = map(&mappedImage);
287
288 mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat),
289 gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, mappedImage.pData);
290
291 unmap();
292 }
daniel@transgaming.coma8aac672012-12-20 21:08:00 +0000293}
294
295void Image11::createStagingTexture()
296{
297 if (mStagingTexture)
298 {
299 return;
300 }
301
302 ID3D11Texture2D *newTexture = NULL;
303 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
304 ASSERT(dxgiFormat != DXGI_FORMAT_D24_UNORM_S8_UINT); // We should never get here for depth textures
305
306 if (mWidth != 0 && mHeight != 0)
307 {
308 ID3D11Device *device = mRenderer->getDevice();
309
310 D3D11_TEXTURE2D_DESC desc;
311 desc.Width = mWidth;
312 desc.Height = mHeight;
313 desc.MipLevels = desc.ArraySize = 1;
314 desc.Format = dxgiFormat;
315 desc.SampleDesc.Count = 1;
316 desc.SampleDesc.Quality = 0;
317 desc.Usage = D3D11_USAGE_STAGING;
318 desc.BindFlags = 0;
319 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
320 desc.MiscFlags = 0;
321
322 HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
323
324 if (FAILED(result))
325 {
326 ASSERT(result == E_OUTOFMEMORY);
327 ERR("Creating image failed.");
328 return error(GL_OUT_OF_MEMORY);
329 }
330 }
331
332 mStagingTexture = newTexture;
333 mDirty = false;
334}
335
336HRESULT Image11::map(D3D11_MAPPED_SUBRESOURCE *map)
337{
338 createStagingTexture();
339
340 HRESULT result = D3DERR_INVALIDCALL;
341
342 if (mStagingTexture)
343 {
344 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
345 result = deviceContext->Map(mStagingTexture, 0, D3D11_MAP_WRITE, 0, map);
346 ASSERT(SUCCEEDED(result));
347
348 mDirty = true;
349 }
350
351 return result;
352}
353
354void Image11::unmap()
355{
356 if (mStagingTexture)
357 {
358 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
359 deviceContext->Unmap(mStagingTexture, 0);
360 }
361}
362
363}