blob: 36dc71ed864b6a819f09c7624dfa44bc15b5777b [file] [log] [blame]
José Fonsecac8695f72013-03-06 12:12:04 +00001/**************************************************************************
2 *
3 * Copyright 2013 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
José Fonsecabbb9eb32013-04-16 19:38:00 +010027#include <assert.h>
28
José Fonseca4bdfcb92013-07-09 13:27:00 +010029#include <iostream>
30
José Fonsecabbb9eb32013-04-16 19:38:00 +010031#include "image.hpp"
José Fonseca29d4bda2014-02-28 17:50:24 +000032#include "json.hpp"
José Fonseca00dc2f12014-06-12 19:18:11 +010033#include "com_ptr.hpp"
José Fonsecabbb9eb32013-04-16 19:38:00 +010034
José Fonsecac8695f72013-03-06 12:12:04 +000035#include "dxgistate.hpp"
José Fonseca29d4bda2014-02-28 17:50:24 +000036#include "d3d10state.hpp"
José Fonseca00dc2f12014-06-12 19:18:11 +010037#ifdef HAVE_D3D11
38#include "d3d11state.hpp"
39#endif
José Fonsecac8695f72013-03-06 12:12:04 +000040
41#ifdef __MINGW32__
42#define nullptr NULL
43#endif
44#include "DirectXTex.h"
45
46
47namespace d3dstate {
48
49
José Fonsecabbb9eb32013-04-16 19:38:00 +010050static DXGI_FORMAT
José Fonseca52fc2b02013-10-10 18:43:33 -070051ChooseConversionFormat(DXGI_FORMAT Format, unsigned &numChannels, image::ChannelType &channelType)
José Fonsecabbb9eb32013-04-16 19:38:00 +010052{
José Fonseca52fc2b02013-10-10 18:43:33 -070053 numChannels = 4;
José Fonseca75af8672013-09-16 12:20:40 +010054 channelType = image::TYPE_UNORM8;
55
José Fonsecabbb9eb32013-04-16 19:38:00 +010056 switch (Format) {
57
58 // Float
59 case DXGI_FORMAT_R32G32B32A32_FLOAT:
60 case DXGI_FORMAT_R32G32B32_FLOAT:
61 case DXGI_FORMAT_R16G16B16A16_FLOAT:
62 case DXGI_FORMAT_R32G32_FLOAT:
63 case DXGI_FORMAT_R11G11B10_FLOAT:
64 case DXGI_FORMAT_R16G16_FLOAT:
65 case DXGI_FORMAT_R32_FLOAT:
66 case DXGI_FORMAT_R16_FLOAT:
67 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
68 case DXGI_FORMAT_BC6H_UF16:
69 case DXGI_FORMAT_BC6H_SF16:
José Fonseca75af8672013-09-16 12:20:40 +010070 channelType = image::TYPE_FLOAT;
71 return DXGI_FORMAT_R32G32B32A32_FLOAT;
José Fonsecabbb9eb32013-04-16 19:38:00 +010072
73 // Unsigned normalized
74 case DXGI_FORMAT_R16G16B16A16_UNORM:
75 case DXGI_FORMAT_R10G10B10A2_UNORM:
76 case DXGI_FORMAT_R8G8B8A8_UNORM:
77 case DXGI_FORMAT_R16G16_UNORM:
78 case DXGI_FORMAT_R8G8_UNORM:
79 case DXGI_FORMAT_R16_UNORM:
80 case DXGI_FORMAT_R8_UNORM:
81 case DXGI_FORMAT_A8_UNORM:
82 case DXGI_FORMAT_R1_UNORM:
83 case DXGI_FORMAT_R8G8_B8G8_UNORM:
84 case DXGI_FORMAT_G8R8_G8B8_UNORM:
85 case DXGI_FORMAT_BC1_UNORM:
86 case DXGI_FORMAT_BC2_UNORM:
87 case DXGI_FORMAT_BC3_UNORM:
88 case DXGI_FORMAT_BC4_UNORM:
89 case DXGI_FORMAT_BC5_UNORM:
90 case DXGI_FORMAT_B5G6R5_UNORM:
91 case DXGI_FORMAT_B5G5R5A1_UNORM:
92 case DXGI_FORMAT_B8G8R8A8_UNORM:
93 case DXGI_FORMAT_B8G8R8X8_UNORM:
94 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
95 case DXGI_FORMAT_BC7_UNORM:
96 return DXGI_FORMAT_R8G8B8A8_UNORM;
97
98 // SRGB
99 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
100 case DXGI_FORMAT_BC1_UNORM_SRGB:
101 case DXGI_FORMAT_BC2_UNORM_SRGB:
102 case DXGI_FORMAT_BC3_UNORM_SRGB:
103 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
104 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
105 case DXGI_FORMAT_BC7_UNORM_SRGB:
106 return DXGI_FORMAT_R8G8B8A8_UNORM;
107
108 // Signed normalized
109 case DXGI_FORMAT_R16G16B16A16_SNORM:
110 case DXGI_FORMAT_R8G8B8A8_SNORM:
111 case DXGI_FORMAT_R16G16_SNORM:
112 case DXGI_FORMAT_R8G8_SNORM:
113 case DXGI_FORMAT_R16_SNORM:
114 case DXGI_FORMAT_R8_SNORM:
115 case DXGI_FORMAT_BC4_SNORM:
116 case DXGI_FORMAT_BC5_SNORM:
117 return DXGI_FORMAT_R8G8B8A8_SNORM;
118
119 // Unsigned
120 case DXGI_FORMAT_R32G32B32A32_UINT:
121 case DXGI_FORMAT_R32G32B32_UINT:
122 case DXGI_FORMAT_R16G16B16A16_UINT:
123 case DXGI_FORMAT_R32G32_UINT:
124 case DXGI_FORMAT_R10G10B10A2_UINT:
125 case DXGI_FORMAT_R8G8B8A8_UINT:
126 case DXGI_FORMAT_R16G16_UINT:
127 case DXGI_FORMAT_R32_UINT:
128 case DXGI_FORMAT_R8G8_UINT:
129 case DXGI_FORMAT_R16_UINT:
130 case DXGI_FORMAT_R8_UINT:
131 return DXGI_FORMAT_R8G8B8A8_UINT;
132
133 // Signed
134 case DXGI_FORMAT_R32G32B32A32_SINT:
135 case DXGI_FORMAT_R32G32B32_SINT:
136 case DXGI_FORMAT_R16G16B16A16_SINT:
137 case DXGI_FORMAT_R32G32_SINT:
138 case DXGI_FORMAT_R8G8B8A8_SINT:
139 case DXGI_FORMAT_R16G16_SINT:
140 case DXGI_FORMAT_R32_SINT:
141 case DXGI_FORMAT_R8G8_SINT:
142 case DXGI_FORMAT_R16_SINT:
143 case DXGI_FORMAT_R8_SINT:
144 return DXGI_FORMAT_R8G8B8A8_SINT;
145
146 // Depth
147 case DXGI_FORMAT_D32_FLOAT:
148 case DXGI_FORMAT_D24_UNORM_S8_UINT:
149 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
150 case DXGI_FORMAT_D16_UNORM:
José Fonseca52fc2b02013-10-10 18:43:33 -0700151 numChannels = 1;
152 channelType = image::TYPE_FLOAT;
153 return DXGI_FORMAT_D32_FLOAT;
José Fonsecabbb9eb32013-04-16 19:38:00 +0100154
155 // Typeless
156 case DXGI_FORMAT_UNKNOWN:
157 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
158 case DXGI_FORMAT_R32G32B32_TYPELESS:
159 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
160 case DXGI_FORMAT_R32G32_TYPELESS:
161 case DXGI_FORMAT_R32G8X24_TYPELESS:
162 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
163 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
164 case DXGI_FORMAT_R16G16_TYPELESS:
165 case DXGI_FORMAT_R32_TYPELESS:
166 case DXGI_FORMAT_R8G8_TYPELESS:
167 case DXGI_FORMAT_R16_TYPELESS:
168 case DXGI_FORMAT_R8_TYPELESS:
169 case DXGI_FORMAT_BC1_TYPELESS:
170 case DXGI_FORMAT_BC2_TYPELESS:
171 case DXGI_FORMAT_BC3_TYPELESS:
172 case DXGI_FORMAT_BC4_TYPELESS:
173 case DXGI_FORMAT_BC5_TYPELESS:
174 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
175 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
176 case DXGI_FORMAT_BC6H_TYPELESS:
177 case DXGI_FORMAT_BC7_TYPELESS:
178 case DXGI_FORMAT_R24G8_TYPELESS:
179 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
180 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
181 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
182 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
183 return DXGI_FORMAT_UNKNOWN;
184
185 default:
186 return DXGI_FORMAT_R8G8B8A8_UNORM;
187 }
188}
189
190
José Fonsecac8695f72013-03-06 12:12:04 +0000191/**
192 * Convert between DXGI formats.
193 *
194 */
195HRESULT
196ConvertFormat(DXGI_FORMAT SrcFormat,
197 void *SrcData,
198 UINT SrcPitch,
199 DXGI_FORMAT DstFormat,
200 void *DstData,
201 UINT DstPitch,
202 UINT Width, UINT Height)
203{
204 HRESULT hr;
205
206 DirectX::Image SrcImage;
207 DirectX::Image DstImage;
208
209 SrcImage.width = Width;
210 SrcImage.height = Height;
211 SrcImage.format = SrcFormat;
212 SrcImage.rowPitch = SrcPitch;
213 SrcImage.slicePitch = Height * SrcPitch;
214 SrcImage.pixels = (uint8_t*)SrcData;
215
216 DstImage.width = Width;
217 DstImage.height = Height;
218 DstImage.format = DstFormat;
219 DstImage.rowPitch = DstPitch;
220 DstImage.slicePitch = Height * DstPitch;
221 DstImage.pixels = (uint8_t*)DstData;
222
223 DirectX::Rect rect(0, 0, Width, Height);
224
José Fonseca386d29d2013-05-20 13:35:23 +0100225 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
226 assert(SUCCEEDED(hr));
227 if (FAILED(hr)) {
228 return hr;
229 }
230
José Fonsecac8695f72013-03-06 12:12:04 +0000231 if (SrcFormat != DstFormat) {
232 DirectX::ScratchImage ScratchImage;
233 ScratchImage.Initialize2D(DstFormat, Width, Height, 1, 1);
234
José Fonseca4bdfcb92013-07-09 13:27:00 +0100235 if (DirectX::IsCompressed(SrcFormat)) {
236 hr = DirectX::Decompress(SrcImage, DstFormat, ScratchImage);
237 } else {
238 hr = DirectX::Convert(SrcImage, DstFormat, DirectX::TEX_FILTER_DEFAULT, 0.0f, ScratchImage);
239 }
240
José Fonsecac8695f72013-03-06 12:12:04 +0000241 if (SUCCEEDED(hr)) {
242 hr = CopyRectangle(*ScratchImage.GetImage(0, 0, 0), rect, DstImage, DirectX::TEX_FILTER_DEFAULT, 0, 0);
243 }
244 } else {
245 hr = CopyRectangle(SrcImage, rect, DstImage, DirectX::TEX_FILTER_DEFAULT, 0, 0);
246 }
247
248 return hr;
249}
250
251
José Fonsecabbb9eb32013-04-16 19:38:00 +0100252image::Image *
253ConvertImage(DXGI_FORMAT SrcFormat,
254 void *SrcData,
255 UINT SrcPitch,
256 UINT Width, UINT Height)
257{
José Fonseca52fc2b02013-10-10 18:43:33 -0700258 unsigned numChannels;
José Fonseca75af8672013-09-16 12:20:40 +0100259 image::ChannelType channelType;
José Fonsecabbb9eb32013-04-16 19:38:00 +0100260
José Fonseca52fc2b02013-10-10 18:43:33 -0700261 DXGI_FORMAT DstFormat = ChooseConversionFormat(SrcFormat, numChannels, channelType);
José Fonsecabbb9eb32013-04-16 19:38:00 +0100262 if (DstFormat == DXGI_FORMAT_UNKNOWN) {
263 return NULL;
264 }
265
José Fonseca52fc2b02013-10-10 18:43:33 -0700266 image::Image *image = new image::Image(Width, Height, numChannels, false, channelType);
José Fonsecabbb9eb32013-04-16 19:38:00 +0100267 if (!image) {
268 return NULL;
269 }
270 assert(image->stride() > 0);
271
272 HRESULT hr;
273 hr = ConvertFormat(SrcFormat,
274 SrcData, SrcPitch,
275 DstFormat,
276 image->start(), image->stride(),
277 Width, Height);
278 if (FAILED(hr)) {
José Fonseca4bdfcb92013-07-09 13:27:00 +0100279 std::cerr << "warning: failed to convert from format " << SrcFormat << " to format " << DstFormat << "\n";
José Fonsecabbb9eb32013-04-16 19:38:00 +0100280 delete image;
281 image = NULL;
282 }
283
284 return image;
285}
286
José Fonseca29d4bda2014-02-28 17:50:24 +0000287
288image::Image *
289getRenderTargetImage(IDXGISwapChain *pSwapChain)
290{
291 HRESULT hr;
292
293 assert(pSwapChain);
294 if (!pSwapChain) {
295 return NULL;
296 }
297
298 DXGI_SWAP_CHAIN_DESC Desc;
299 hr = pSwapChain->GetDesc(&Desc);
300 assert(SUCCEEDED(hr));
301
302 /*
303 * There is a IDXGISurface::Map method, but swapchains are not normally mappable,
304 * and there is no way to copy into a staging resource, which effectively means there
305 * is no way to read a IDXGISwapChain using DXGI interfaces alone.
306 *
307 * We must figure out
308 * the appropriate D3D10/D3D11 interfaces, and use them instead.
309 */
310
José Fonseca00dc2f12014-06-12 19:18:11 +0100311 com_ptr<ID3D10Device> pD3D10Device;
312 hr = pSwapChain->GetDevice(IID_ID3D10Device, (void **)&pD3D10Device);
José Fonseca29d4bda2014-02-28 17:50:24 +0000313 if (SUCCEEDED(hr)) {
José Fonseca00dc2f12014-06-12 19:18:11 +0100314 ID3D10Resource *pD3D10Resource = NULL;
315 hr = pSwapChain->GetBuffer(0, IID_ID3D10Resource, (void **)&pD3D10Resource);
José Fonseca29d4bda2014-02-28 17:50:24 +0000316 assert(SUCCEEDED(hr));
317 if (FAILED(hr)) {
318 return NULL;
319 }
320
321 DXGI_FORMAT Format = Desc.BufferDesc.Format;
322
323 return getSubResourceImage(pD3D10Device, pD3D10Resource, Format, 0, 0);
324 }
325
José Fonseca00dc2f12014-06-12 19:18:11 +0100326#ifdef HAVE_D3D11
327 com_ptr<ID3D11Device> pD3D11Device;
328 hr = pSwapChain->GetDevice(IID_ID3D11Device, (void **)&pD3D11Device);
329 if (SUCCEEDED(hr)) {
330 ID3D11Resource *pD3D11Resource = NULL;
331 hr = pSwapChain->GetBuffer(0, IID_ID3D11Resource, (void **)&pD3D11Resource);
332 assert(SUCCEEDED(hr));
333 if (FAILED(hr)) {
334 return NULL;
335 }
336
337 com_ptr<ID3D11DeviceContext> pD3D11DeviceContext;
338 pD3D11Device->GetImmediateContext(&pD3D11DeviceContext);
339
340 DXGI_FORMAT Format = Desc.BufferDesc.Format;
341
342 return getSubResourceImage(pD3D11DeviceContext, pD3D11Resource, Format, 0, 0);
343 }
344#endif
José Fonseca29d4bda2014-02-28 17:50:24 +0000345
346 return NULL;
347}
348
349
350void
351dumpDevice(std::ostream &os, IDXGISwapChain *pSwapChain)
352{
353 JSONWriter json(os);
354
355 json.beginMember("framebuffer");
356 json.beginObject();
357
358 if (pSwapChain) {
359 image::Image *image;
360 image = getRenderTargetImage(pSwapChain);
361 if (image) {
362 json.beginMember("SWAP_CHAIN");
363 json.writeImage(image, "UNKNOWN");
364 json.endMember();
365 }
366 }
367
368 json.endObject();
369 json.endMember(); // framebuffer
370}
371
372
José Fonsecac8695f72013-03-06 12:12:04 +0000373} /* namespace d3dstate */