1 /**************************************************************************
2  *
3  * Copyright 2012 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sub license,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20  * AUTHORS,
21  * AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *
26  **************************************************************************/
27 
28 
29 /*
30  * Auxiliary functions to compute the size of array/blob arguments.
31  */
32 
33 #pragma once
34 
35 
36 /* We purposedly don't include any D3D header, so that this header can be used
37  * with all D3D versions. */
38 
39 #include <assert.h>
40 
41 #include <algorithm>
42 
43 #include "os.hpp"
44 
45 
46 static inline size_t
_vertexCount(D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount)47 _vertexCount(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount)
48 {
49     switch (PrimitiveType) {
50     case D3DPT_POINTLIST:
51         return PrimitiveCount;
52     case D3DPT_LINELIST:
53         return PrimitiveCount*2;
54     case D3DPT_LINESTRIP:
55         return PrimitiveCount + 1;
56     case D3DPT_TRIANGLELIST:
57         return PrimitiveCount * 3;
58     case D3DPT_TRIANGLESTRIP:
59         return PrimitiveCount + 2;
60     case D3DPT_TRIANGLEFAN:
61         return PrimitiveCount + 2;
62     default:
63         os::log("apitrace: warning: %s: unknown D3DPRIMITIVETYPE %u\n", __FUNCTION__, PrimitiveType);
64         return 0;
65     }
66 }
67 
68 
69 static inline size_t
_vertexDataSize(D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,UINT VertexStride)70 _vertexDataSize(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, UINT VertexStride) {
71     return _vertexCount(PrimitiveType, PrimitiveCount) * VertexStride;
72 }
73 
74 
75 static inline size_t
_indexDataSize(D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,D3DFORMAT IndexDataFormat)76 _indexDataSize(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, D3DFORMAT IndexDataFormat) {
77     UINT IndexStride;
78     switch (IndexDataFormat) {
79     case D3DFMT_INDEX16:
80         IndexStride = 2;
81         break;
82     case D3DFMT_INDEX32:
83         IndexStride = 4;
84         break;
85     default:
86         os::log("apitrace: warning: %s: unexpected index D3DFORMAT %u\n", __FUNCTION__, IndexDataFormat);
87         return 0;
88     }
89     return _vertexCount(PrimitiveType, PrimitiveCount) * IndexStride;
90 }
91 
92 
93 /*
94  * Return the number of tokens for a given shader.
95  */
96 static inline size_t
_shaderSize(const DWORD * pFunction)97 _shaderSize(const DWORD *pFunction)
98 {
99     DWORD dwLength = 0;
100 
101     // Version token
102     // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/version-token
103     DWORD dwVersion = pFunction[dwLength++];
104 
105     if (D3DSHADER_VERSION_MAJOR(dwVersion) >= 2) {
106         // Advance tokens using instruction length
107         // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/instruction-token
108         while (true) {
109             DWORD dwToken = pFunction[dwLength++];
110             D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode = D3DSHADER_INSTRUCTION_OPCODE_TYPE(dwToken & D3DSI_OPCODE_MASK);
111             switch (opcode) {
112             case D3DSIO_COMMENT:
113                 dwLength += (dwToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
114                 break;
115 
116             case D3DSIO_END:
117                 assert(dwToken == D3DSIO_END);
118                 if (dwToken == D3DSIO_END) {
119                     return dwLength * sizeof *pFunction;
120                 }
121                 break;
122 
123             default:
124                 dwLength += (dwToken & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT;
125                 break;
126             }
127         }
128     } else {
129         // Advance tokens using bit 31
130         while (true) {
131             DWORD dwToken = pFunction[dwLength++];
132 
133             // Skip Destination/Source/Label tokens
134             if (dwToken & 0x80000000U) {
135                 continue;
136             }
137 
138             D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode = D3DSHADER_INSTRUCTION_OPCODE_TYPE(dwToken & D3DSI_OPCODE_MASK);
139             switch (opcode) {
140             case D3DSIO_COMMENT:
141                 dwLength += (dwToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
142                 break;
143 
144             case D3DSIO_DEF:
145                 // Contains raw floating point so can't be advanced with the 31 bit test.
146                 // NOTE: DEFB/DEFI are SM 2 only.
147                 dwLength += 5;
148                 break;
149 
150             case D3DSIO_END:
151                 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/end-token
152                 if (dwToken == D3DSIO_END) {
153                     return dwLength * sizeof *pFunction;
154                 }
155                 break;
156 
157             default:
158                 break;
159             }
160         }
161     }
162 }
163 
164 
165 static inline void
166 _getFormatSize(D3DFORMAT Format, size_t & BlockSize, UINT & BlockWidth, UINT & BlockHeight);
167 
168 #define PACKED_PITCH 0x7ffffff
169 
170 static inline size_t
_getLockSize(D3DFORMAT Format,bool Partial,UINT Width,UINT Height,INT RowPitch=PACKED_PITCH,UINT Depth=1,INT SlicePitch=0)171 _getLockSize(D3DFORMAT Format, bool Partial, UINT Width, UINT Height, INT RowPitch = PACKED_PITCH, UINT Depth = 1, INT SlicePitch = 0) {
172     if (Width == 0 || Height == 0 || Depth == 0) {
173         return 0;
174     }
175 
176     if (RowPitch < 0) {
177         os::log("apitrace: warning: %s: negative row pitch %i\n", __FUNCTION__, RowPitch);
178         return 0;
179     }
180 
181     size_t size;
182     if (Format == MAKEFOURCC('N','V','1','2') ||
183         Format == MAKEFOURCC('Y','V','1','2')) {
184         // Planar YUV
185 
186         if (RowPitch == PACKED_PITCH) {
187             RowPitch = Width;
188         }
189 
190         size = (Height + (Height + 1)/2) * RowPitch;
191     } else if (Format == MAKEFOURCC('A','T','I','1')) {
192         // 64 bits per 4x4 block, but limited to height*pitch
193 
194         if (RowPitch == PACKED_PITCH) {
195             RowPitch = Width;
196         }
197 
198         size = std::min(Height * RowPitch,  ((Height + 3)/4) * ((Width + 3)/4) * (64 / 8));
199     } else if (Format == MAKEFOURCC('A','T','I','2')) {
200         // 128 bits per 4x4 block, but limited to height*pitch
201 
202         if (RowPitch == PACKED_PITCH) {
203             RowPitch = Width;
204         }
205 
206         size = std::min(Height * RowPitch,  ((Height + 3)/4) * ((Width + 3)/4) * (128 / 8));
207     } else {
208         size_t BlockSize;
209         UINT BlockWidth;
210         UINT BlockHeight;
211         _getFormatSize(Format, BlockSize, BlockWidth, BlockHeight);
212         assert(BlockHeight);
213         Height = (Height + BlockHeight - 1) / BlockHeight;
214 
215         if (RowPitch == PACKED_PITCH) {
216             RowPitch = ((Width + BlockWidth  - 1) / BlockWidth * BlockSize + 7) / 8;
217         }
218 
219         size = Height * RowPitch;
220 
221         if (Partial || Height == 1) {
222             // Must take pixel size in consideration
223             if (BlockWidth) {
224                 Width = (Width + BlockWidth  - 1) / BlockWidth;
225                 size = (Width * BlockSize + 7) / 8;
226                 if (Height > 1) {
227                     size += (Height - 1) * RowPitch;
228                 }
229             }
230         }
231     }
232 
233     if (Depth > 1) {
234         if (SlicePitch < 0) {
235             os::log("apitrace: warning: %s: negative slice pitch %i\n", __FUNCTION__, SlicePitch);
236             return 0;
237         }
238 
239         size += (Depth - 1) * SlicePitch;
240     }
241 
242     return size;
243 }
244 
245 
246