]> git.cworth.org Git - apitrace/blob - retrace/d3d10state_images.cpp
retrace: Move JSON write implementation to a .cpp file.
[apitrace] / retrace / d3d10state_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 "d3d10imports.hpp"
34
35
36 namespace d3dstate {
37
38 static HRESULT
39 stageResource(ID3D10Device *pDevice,
40               ID3D10Resource *pResource,
41               ID3D10Resource **ppStagingResource,
42               UINT *pWidth, UINT *pHeight, UINT *pDepth) {
43     D3D10_USAGE Usage = D3D10_USAGE_STAGING;
44     UINT BindFlags = 0;
45     UINT CPUAccessFlags = D3D10_CPU_ACCESS_READ;
46     UINT MiscFlags = 0;
47     union {
48          ID3D10Resource *pStagingResource;
49          ID3D10Buffer *pStagingBuffer;
50          ID3D10Texture1D *pStagingTexture1D;
51          ID3D10Texture2D *pStagingTexture2D;
52          ID3D10Texture3D *pStagingTexture3D;
53     };
54     HRESULT hr;
55
56     D3D10_RESOURCE_DIMENSION Type = D3D10_RESOURCE_DIMENSION_UNKNOWN;
57     pResource->GetType(&Type);
58     switch (Type) {
59     case D3D10_RESOURCE_DIMENSION_BUFFER:
60         {
61             D3D10_BUFFER_DESC Desc;
62             static_cast<ID3D10Buffer *>(pResource)->GetDesc(&Desc);
63             Desc.Usage = Usage;
64             Desc.BindFlags = BindFlags;
65             Desc.CPUAccessFlags = CPUAccessFlags;
66             Desc.MiscFlags = MiscFlags;
67
68             *pWidth = Desc.ByteWidth;
69             *pHeight = 1;
70             *pDepth = 1;
71
72             hr = pDevice->CreateBuffer(&Desc, NULL, &pStagingBuffer);
73         }
74         break;
75     case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
76         {
77             D3D10_TEXTURE1D_DESC Desc;
78             static_cast<ID3D10Texture1D *>(pResource)->GetDesc(&Desc);
79             Desc.Usage = Usage;
80             Desc.BindFlags = BindFlags;
81             Desc.CPUAccessFlags = CPUAccessFlags;
82             Desc.MiscFlags = MiscFlags;
83
84             *pWidth = Desc.Width;
85             *pHeight = 1;
86             *pDepth = 1;
87
88             hr = pDevice->CreateTexture1D(&Desc, NULL, &pStagingTexture1D);
89         }
90         break;
91     case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
92         {
93             D3D10_TEXTURE2D_DESC Desc;
94             static_cast<ID3D10Texture2D *>(pResource)->GetDesc(&Desc);
95             Desc.Usage = Usage;
96             Desc.BindFlags = BindFlags;
97             Desc.CPUAccessFlags = CPUAccessFlags;
98             Desc.MiscFlags &= D3D10_RESOURCE_MISC_TEXTURECUBE;
99
100             *pWidth = Desc.Width;
101             *pHeight = Desc.Height;
102             *pDepth = 1;
103
104             hr = pDevice->CreateTexture2D(&Desc, NULL, &pStagingTexture2D);
105         }
106         break;
107     case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
108         {
109             D3D10_TEXTURE3D_DESC Desc;
110             static_cast<ID3D10Texture3D *>(pResource)->GetDesc(&Desc);
111             Desc.Usage = Usage;
112             Desc.BindFlags = BindFlags;
113             Desc.CPUAccessFlags = CPUAccessFlags;
114             Desc.MiscFlags = MiscFlags;
115
116             *pWidth = Desc.Width;
117             *pHeight = Desc.Height;
118             *pDepth = Desc.Depth;
119
120             hr = pDevice->CreateTexture3D(&Desc, NULL, &pStagingTexture3D);
121         }
122         break;
123     default:
124         assert(0);
125         hr = E_NOTIMPL;
126         break;
127     }
128
129     if (SUCCEEDED(hr)) {
130         *ppStagingResource = pStagingResource;
131         pDevice->CopyResource(pStagingResource, pResource);
132     }
133     
134     return hr;
135 }
136
137 static HRESULT
138 mapResource(ID3D10Resource *pResource,
139             UINT Subresource, D3D10_MAP MapType, UINT MapFlags,
140             D3D10_MAPPED_TEXTURE3D *pMappedSubresource) {
141     D3D10_RESOURCE_DIMENSION Type = D3D10_RESOURCE_DIMENSION_UNKNOWN;
142     pResource->GetType(&Type);
143     switch (Type) {
144     case D3D10_RESOURCE_DIMENSION_BUFFER:
145         assert(Subresource == 0);
146         return static_cast<ID3D10Buffer *>(pResource)->Map(MapType, MapFlags, &pMappedSubresource->pData);
147     case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
148         return static_cast<ID3D10Texture1D *>(pResource)->Map(Subresource, MapType, MapFlags, &pMappedSubresource->pData);
149     case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
150         return static_cast<ID3D10Texture2D *>(pResource)->Map(Subresource, MapType, MapFlags, reinterpret_cast<D3D10_MAPPED_TEXTURE2D *>(pMappedSubresource));
151     case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
152         return static_cast<ID3D10Texture3D *>(pResource)->Map(Subresource, MapType, MapFlags, pMappedSubresource);
153     default:
154         assert(0);
155         return E_NOTIMPL;
156     }
157 }
158
159 static void
160 unmapResource(ID3D10Resource *pResource, UINT Subresource) {
161     D3D10_RESOURCE_DIMENSION Type = D3D10_RESOURCE_DIMENSION_UNKNOWN;
162     pResource->GetType(&Type);
163     switch (Type) {
164     case D3D10_RESOURCE_DIMENSION_BUFFER:
165         assert(Subresource == 0);
166         static_cast<ID3D10Buffer *>(pResource)->Unmap();
167         break;
168     case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
169         static_cast<ID3D10Texture1D *>(pResource)->Unmap(Subresource);
170         break;
171     case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
172         static_cast<ID3D10Texture2D *>(pResource)->Unmap(Subresource);
173         break;
174     case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
175         static_cast<ID3D10Texture3D *>(pResource)->Unmap(Subresource);
176         break;
177     default:
178         assert(0);
179     }
180 }
181
182 image::Image *
183 getRenderTargetImage(ID3D10Device *pDevice) {
184     image::Image *image = NULL;
185     ID3D10RenderTargetView *pRenderTargetView = NULL;
186     D3D10_RENDER_TARGET_VIEW_DESC Desc;
187     ID3D10Resource *pResource = NULL;
188     ID3D10Resource *pStagingResource = NULL;
189     UINT Width, Height, Depth;
190     UINT MipSlice;
191     UINT Subresource;
192     D3D10_MAPPED_TEXTURE3D MappedSubresource;
193     HRESULT hr;
194     const unsigned char *src;
195     unsigned char *dst;
196
197     pDevice->OMGetRenderTargets(1, &pRenderTargetView, NULL);
198     if (!pRenderTargetView) {
199         goto no_rendertarget;
200     }
201
202     pRenderTargetView->GetResource(&pResource);
203     assert(pResource);
204
205     pRenderTargetView->GetDesc(&Desc);
206     if (Desc.Format != DXGI_FORMAT_R8G8B8A8_UNORM &&
207         Desc.Format != DXGI_FORMAT_R32G32B32A32_FLOAT &&
208         Desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) {
209         std::cerr << "warning: unsupported DXGI format " << Desc.Format << "\n";
210         goto no_staging;
211     }
212
213     hr = stageResource(pDevice, pResource, &pStagingResource, &Width, &Height, &Depth);
214     if (FAILED(hr)) {
215         goto no_staging;
216     }
217
218     // TODO: Take the slice in consideration
219     switch (Desc.ViewDimension) {
220     case D3D10_RTV_DIMENSION_BUFFER:
221         MipSlice = 0;
222         break;
223     case D3D10_RTV_DIMENSION_TEXTURE1D:
224         MipSlice = Desc.Texture1D.MipSlice;
225         break;
226     case D3D10_RTV_DIMENSION_TEXTURE1DARRAY:
227         MipSlice = Desc.Texture1DArray.MipSlice;
228         break;
229     case D3D10_RTV_DIMENSION_TEXTURE2D:
230         MipSlice = Desc.Texture2D.MipSlice;
231         MipSlice = 0;
232         break;
233     case D3D10_RTV_DIMENSION_TEXTURE2DARRAY:
234         MipSlice = Desc.Texture2DArray.MipSlice;
235         break;
236     case D3D10_RTV_DIMENSION_TEXTURE2DMS:
237         MipSlice = 0;
238         break;
239     case D3D10_RTV_DIMENSION_TEXTURE2DMSARRAY:
240         MipSlice = 0;
241         break;
242     case D3D10_RTV_DIMENSION_TEXTURE3D:
243         MipSlice = Desc.Texture3D.MipSlice;
244         break;
245     case D3D10_SRV_DIMENSION_UNKNOWN:
246     default:
247         assert(0);
248         goto no_map;
249     }
250     Subresource = MipSlice;
251
252     Width  = std::max(Width  >> MipSlice, 1U);
253     Height = std::max(Height >> MipSlice, 1U);
254     Depth  = std::max(Depth  >> MipSlice, 1U);
255
256     hr = mapResource(pStagingResource, Subresource, D3D10_MAP_READ, 0, &MappedSubresource);
257     if (FAILED(hr)) {
258         goto no_map;
259     }
260
261     image = new image::Image(Width, Height, 4, true);
262     if (!image) {
263         goto no_image;
264     }
265
266     dst = image->start();
267     src = (const unsigned char *)MappedSubresource.pData;
268     for (unsigned y = 0; y < Height; ++y) {
269         if (Desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM) {
270             memcpy(dst, src, Width * 4);
271         } else if (Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT) {
272             float scale = 1.0f/255.0f;
273             for (unsigned x = 0; x < Width; ++x) {
274                 dst[4*x + 0] = ((float *)src)[4*x + 0] * scale;
275                 dst[4*x + 1] = ((float *)src)[4*x + 1] * scale;
276                 dst[4*x + 2] = ((float *)src)[4*x + 2] * scale;
277                 dst[4*x + 3] = ((float *)src)[4*x + 3] * scale;
278             }
279         } else if (Desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM) {
280             for (unsigned x = 0; x < Width; ++x) {
281                 dst[4*x + 0] = src[4*x + 2];
282                 dst[4*x + 1] = src[4*x + 1];
283                 dst[4*x + 2] = src[4*x + 0];
284                 dst[4*x + 3] = src[4*x + 3];
285             }
286         } else {
287             assert(0);
288         }
289         src += MappedSubresource.RowPitch;
290         dst += image->stride();
291     }
292
293 no_image:
294     unmapResource(pStagingResource, Subresource);
295 no_map:
296     if (pStagingResource) {
297         pStagingResource->Release();
298     }
299 no_staging:
300     if (pResource) {
301         pResource->Release();
302     }
303     if (pRenderTargetView) {
304         pRenderTargetView->Release();
305     }
306 no_rendertarget:
307     return image;
308 }
309
310
311 } /* namespace d3dstate */