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