|
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(&destMapped); |
|
54 src->map(&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(&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(&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(&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_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_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, D3D11_MAP_WRITE, 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 } |