]> git.cworth.org Git - apitrace/blob - retrace/d3d11state_images.cpp
d3d11state: Use DirectXTex for format conversion.
[apitrace] / retrace / d3d11state_images.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
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
27 #include <assert.h>
28
29 #include <iostream>
30 #include <algorithm>
31
32 #include "image.hpp"
33 #include "d3d11imports.hpp"
34 #include "d3d10state.hpp"
35
36 #ifdef __MINGW32__
37 #define nullptr NULL
38 #endif
39 #include "DirectXTex.h"
40
41
42 /**
43  * Convert between DXGI formats.
44  *
45  */
46 static HRESULT
47 ConvertFormat(DXGI_FORMAT SrcFormat,
48               void *SrcData,
49               UINT SrcPitch,
50               DXGI_FORMAT DstFormat,
51               void *DstData,
52               UINT DstPitch,
53               UINT Width, UINT Height)
54 {
55     HRESULT hr;
56
57     DirectX::Image SrcImage;
58     DirectX::Image DstImage;
59     
60     SrcImage.width = Width;
61     SrcImage.height = Height;
62     SrcImage.format = SrcFormat;
63     SrcImage.rowPitch = SrcPitch;
64     SrcImage.slicePitch = Height * SrcPitch;
65     SrcImage.pixels = (uint8_t*)SrcData;
66     
67     DstImage.width = Width;
68     DstImage.height = Height;
69     DstImage.format = DstFormat;
70     DstImage.rowPitch = DstPitch;
71     DstImage.slicePitch = Height * DstPitch;
72     DstImage.pixels = (uint8_t*)DstData;
73  
74     DirectX::Rect rect(0, 0, Width, Height);
75  
76     if (SrcFormat != DstFormat) {
77         DirectX::ScratchImage ScratchImage;
78         ScratchImage.Initialize2D(DstFormat, Width, Height, 1, 1);
79   
80         hr = DirectX::Convert(SrcImage, DstFormat, DirectX::TEX_FILTER_DEFAULT, 0.0f, ScratchImage);
81         if (SUCCEEDED(hr)) {
82             hr = CopyRectangle(*ScratchImage.GetImage(0, 0, 0), rect, DstImage, DirectX::TEX_FILTER_DEFAULT, 0, 0);
83         }
84     } else {
85         hr = CopyRectangle(SrcImage, rect, DstImage, DirectX::TEX_FILTER_DEFAULT, 0, 0);
86     }
87  
88     return hr;
89 }
90
91
92 namespace d3dstate {
93
94 static HRESULT
95 stageResource(ID3D11DeviceContext *pDeviceContext,
96               ID3D11Resource *pResource,
97               ID3D11Resource **ppStagingResource,
98               UINT *pWidth, UINT *pHeight, UINT *pDepth) {
99     D3D11_USAGE Usage = D3D11_USAGE_STAGING;
100     UINT BindFlags = 0;
101     UINT CPUAccessFlags = D3D11_CPU_ACCESS_READ;
102     UINT MiscFlags = 0;
103     union {
104          ID3D11Resource *pStagingResource;
105          ID3D11Buffer *pStagingBuffer;
106          ID3D11Texture1D *pStagingTexture1D;
107          ID3D11Texture2D *pStagingTexture2D;
108          ID3D11Texture3D *pStagingTexture3D;
109     };
110     HRESULT hr;
111
112     ID3D11Device *pDevice = NULL;
113     pDeviceContext->GetDevice(&pDevice);
114
115     D3D11_RESOURCE_DIMENSION Type = D3D11_RESOURCE_DIMENSION_UNKNOWN;
116     pResource->GetType(&Type);
117     switch (Type) {
118     case D3D11_RESOURCE_DIMENSION_BUFFER:
119         {
120             D3D11_BUFFER_DESC Desc;
121             static_cast<ID3D11Buffer *>(pResource)->GetDesc(&Desc);
122             Desc.Usage = Usage;
123             Desc.BindFlags = BindFlags;
124             Desc.CPUAccessFlags = CPUAccessFlags;
125             Desc.MiscFlags = MiscFlags;
126
127             *pWidth = Desc.ByteWidth;
128             *pHeight = 1;
129             *pDepth = 1;
130
131             hr = pDevice->CreateBuffer(&Desc, NULL, &pStagingBuffer);
132         }
133         break;
134     case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
135         {
136             D3D11_TEXTURE1D_DESC Desc;
137             static_cast<ID3D11Texture1D *>(pResource)->GetDesc(&Desc);
138             Desc.Usage = Usage;
139             Desc.BindFlags = BindFlags;
140             Desc.CPUAccessFlags = CPUAccessFlags;
141             Desc.MiscFlags = MiscFlags;
142
143             *pWidth = Desc.Width;
144             *pHeight = 1;
145             *pDepth = 1;
146
147             hr = pDevice->CreateTexture1D(&Desc, NULL, &pStagingTexture1D);
148         }
149         break;
150     case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
151         {
152             D3D11_TEXTURE2D_DESC Desc;
153             static_cast<ID3D11Texture2D *>(pResource)->GetDesc(&Desc);
154             Desc.Usage = Usage;
155             Desc.BindFlags = BindFlags;
156             Desc.CPUAccessFlags = CPUAccessFlags;
157             Desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;
158
159             *pWidth = Desc.Width;
160             *pHeight = Desc.Height;
161             *pDepth = 1;
162
163             hr = pDevice->CreateTexture2D(&Desc, NULL, &pStagingTexture2D);
164         }
165         break;
166     case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
167         {
168             D3D11_TEXTURE3D_DESC Desc;
169             static_cast<ID3D11Texture3D *>(pResource)->GetDesc(&Desc);
170             Desc.Usage = Usage;
171             Desc.BindFlags = BindFlags;
172             Desc.CPUAccessFlags = CPUAccessFlags;
173             Desc.MiscFlags = MiscFlags;
174
175             *pWidth = Desc.Width;
176             *pHeight = Desc.Height;
177             *pDepth = Desc.Depth;
178
179             hr = pDevice->CreateTexture3D(&Desc, NULL, &pStagingTexture3D);
180         }
181         break;
182     default:
183         assert(0);
184         hr = E_NOTIMPL;
185         break;
186     }
187
188     if (SUCCEEDED(hr)) {
189         *ppStagingResource = pStagingResource;
190         pDeviceContext->CopyResource(pStagingResource, pResource);
191     }
192     
193     pDevice->Release();
194
195     return hr;
196 }
197
198 image::Image *
199 getRenderTargetViewImage(ID3D11DeviceContext *pDevice,
200                          ID3D11RenderTargetView *pRenderTargetView) {
201     image::Image *image = NULL;
202     D3D11_RENDER_TARGET_VIEW_DESC Desc;
203     ID3D11Resource *pResource = NULL;
204     ID3D11Resource *pStagingResource = NULL;
205     UINT Width, Height, Depth;
206     UINT MipSlice;
207     UINT Subresource;
208     D3D11_MAPPED_SUBRESOURCE MappedSubresource;
209     HRESULT hr;
210
211     if (!pRenderTargetView) {
212         return NULL;
213     }
214
215     pRenderTargetView->GetResource(&pResource);
216     assert(pResource);
217
218     pRenderTargetView->GetDesc(&Desc);
219
220     hr = stageResource(pDevice, pResource, &pStagingResource, &Width, &Height, &Depth);
221     if (FAILED(hr)) {
222         goto no_staging;
223     }
224
225     // TODO: Take the slice in consideration
226     switch (Desc.ViewDimension) {
227     case D3D11_RTV_DIMENSION_BUFFER:
228         MipSlice = 0;
229         break;
230     case D3D11_RTV_DIMENSION_TEXTURE1D:
231         MipSlice = Desc.Texture1D.MipSlice;
232         break;
233     case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
234         MipSlice = Desc.Texture1DArray.MipSlice;
235         break;
236     case D3D11_RTV_DIMENSION_TEXTURE2D:
237         MipSlice = Desc.Texture2D.MipSlice;
238         MipSlice = 0;
239         break;
240     case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
241         MipSlice = Desc.Texture2DArray.MipSlice;
242         break;
243     case D3D11_RTV_DIMENSION_TEXTURE2DMS:
244         MipSlice = 0;
245         break;
246     case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
247         MipSlice = 0;
248         break;
249     case D3D11_RTV_DIMENSION_TEXTURE3D:
250         MipSlice = Desc.Texture3D.MipSlice;
251         break;
252     case D3D11_SRV_DIMENSION_UNKNOWN:
253     default:
254         assert(0);
255         goto no_map;
256     }
257     Subresource = MipSlice;
258
259     Width  = std::max(Width  >> MipSlice, 1U);
260     Height = std::max(Height >> MipSlice, 1U);
261     Depth  = std::max(Depth  >> MipSlice, 1U);
262
263     hr = pDevice->Map(pStagingResource, Subresource, D3D11_MAP_READ, 0, &MappedSubresource);
264     if (FAILED(hr)) {
265         goto no_map;
266     }
267
268     image = new image::Image(Width, Height, 4);
269     if (!image) {
270         goto no_image;
271     }
272     assert(image->stride() > 0);
273
274     hr = ConvertFormat(Desc.Format,
275                        MappedSubresource.pData,
276                        MappedSubresource.RowPitch,
277                        DXGI_FORMAT_R8G8B8A8_UNORM,
278                        image->start(),
279                        image->stride(),
280                        Width, Height);
281     if (FAILED(hr)) {
282         delete image;
283         image = NULL;
284     }
285
286 no_image:
287     pDevice->Unmap(pStagingResource, Subresource);
288 no_map:
289     if (pStagingResource) {
290         pStagingResource->Release();
291     }
292 no_staging:
293     if (pResource) {
294         pResource->Release();
295     }
296     return image;
297 }
298
299
300
301
302 image::Image *
303 getRenderTargetImage(ID3D11DeviceContext *pDevice) {
304     ID3D11RenderTargetView *pRenderTargetView = NULL;
305     pDevice->OMGetRenderTargets(1, &pRenderTargetView, NULL);
306
307     image::Image *image = NULL;
308     if (pRenderTargetView) {
309         image = getRenderTargetViewImage(pDevice, pRenderTargetView);
310         pRenderTargetView->Release();
311     }
312
313     return image;
314 }
315
316
317 void
318 dumpFramebuffer(JSONWriter &json, ID3D11DeviceContext *pDevice)
319 {
320     json.beginMember("framebuffer");
321     json.beginObject();
322
323     ID3D11RenderTargetView *pRenderTargetViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
324     pDevice->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, pRenderTargetViews, NULL);
325
326     for (UINT i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
327         if (!pRenderTargetViews[i]) {
328             continue;
329         }
330
331         image::Image *image;
332         image = getRenderTargetViewImage(pDevice, pRenderTargetViews[i]);
333         if (image) {
334             char label[64];
335             _snprintf(label, sizeof label, "RENDER_TARGET_%u", i);
336             json.beginMember(label);
337             json.writeImage(image, "UNKNOWN");
338             json.endMember(); // RENDER_TARGET_*
339         }
340
341         pRenderTargetViews[i]->Release();
342     }
343
344     json.endObject();
345     json.endMember(); // framebuffer
346 }
347
348
349 } /* namespace d3dstate */