2 * Direct3D bytecode output functions
4 * Copyright 2008 Stefan Dösinger
5 * Copyright 2009 Matteo Bruni
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
25 #include "wine/debug.h"
27 #include "d3dx9_36_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(asmshader
);
31 /****************************************************************
32 * General assembler shader construction helper routines follow *
33 ****************************************************************/
34 /* struct instruction *alloc_instr
36 * Allocates a new instruction structure with srcs registers
39 * srcs: Number of source registers to allocate
42 * A pointer to the allocated instruction structure
43 * NULL in case of an allocation failure
45 struct instruction
*alloc_instr(unsigned int srcs
) {
46 struct instruction
*ret
= asm_alloc(sizeof(*ret
));
48 ERR("Failed to allocate memory for an instruction structure\n");
53 ret
->src
= asm_alloc(srcs
* sizeof(*ret
->src
));
55 ERR("Failed to allocate memory for instruction registers\n");
64 /* void add_instruction
66 * Adds a new instruction to the shader's instructions array and grows the instruction array
69 * The function does NOT copy the instruction structure. Make sure not to release the
70 * instruction or any of its substructures like registers.
73 * shader: Shader to add the instruction to
74 * instr: Instruction to add to the shader
76 BOOL
add_instruction(struct bwriter_shader
*shader
, struct instruction
*instr
) {
77 struct instruction
**new_instructions
;
79 if(!shader
) return FALSE
;
81 if(shader
->instr_alloc_size
== 0) {
82 shader
->instr
= asm_alloc(sizeof(*shader
->instr
) * INSTRARRAY_INITIAL_SIZE
);
84 ERR("Failed to allocate the shader instruction array\n");
87 shader
->instr_alloc_size
= INSTRARRAY_INITIAL_SIZE
;
88 } else if(shader
->instr_alloc_size
== shader
->num_instrs
) {
89 new_instructions
= asm_realloc(shader
->instr
,
90 sizeof(*shader
->instr
) * (shader
->instr_alloc_size
) * 2);
91 if(!new_instructions
) {
92 ERR("Failed to grow the shader instruction array\n");
95 shader
->instr
= new_instructions
;
96 shader
->instr_alloc_size
= shader
->instr_alloc_size
* 2;
97 } else if(shader
->num_instrs
> shader
->instr_alloc_size
) {
98 ERR("More instructions than allocated. This should not happen\n");
102 shader
->instr
[shader
->num_instrs
] = instr
;
103 shader
->num_instrs
++;
107 /* shader bytecode buffer manipulation functions.
108 * allocate_buffer creates a new buffer structure, put_dword adds a new
109 * DWORD to the buffer. In the rare case of a memory allocation failure
110 * when trying to grow the buffer a flag is set in the buffer to mark it
111 * invalid. This avoids return value checking and passing in many places
113 static struct bytecode_buffer
*allocate_buffer(void) {
114 struct bytecode_buffer
*ret
;
116 ret
= asm_alloc(sizeof(*ret
));
117 if(!ret
) return NULL
;
119 ret
->alloc_size
= BYTECODEBUFFER_INITIAL_SIZE
;
120 ret
->data
= asm_alloc(sizeof(DWORD
) * ret
->alloc_size
);
129 static void put_dword(struct bytecode_buffer
*buffer
, DWORD value
) {
130 if(FAILED(buffer
->state
)) return;
132 if(buffer
->alloc_size
== buffer
->size
) {
134 buffer
->alloc_size
*= 2;
135 newarray
= asm_realloc(buffer
->data
,
136 sizeof(DWORD
) * buffer
->alloc_size
);
138 ERR("Failed to grow the buffer data memory\n");
139 buffer
->state
= E_OUTOFMEMORY
;
142 buffer
->data
= newarray
;
144 buffer
->data
[buffer
->size
++] = value
;
147 /******************************************************
148 * Implementation of the writer functions starts here *
149 ******************************************************/
150 static void end(struct bc_writer
*This
, const struct bwriter_shader
*shader
, struct bytecode_buffer
*buffer
) {
151 put_dword(buffer
, D3DSIO_END
);
154 static void write_srcregs(struct bc_writer
*This
, const struct instruction
*instr
,
155 struct bytecode_buffer
*buffer
){
157 if(instr
->has_predicate
){
158 This
->funcs
->srcreg(This
, &instr
->predicate
, buffer
);
160 for(i
= 0; i
< instr
->num_srcs
; i
++){
161 This
->funcs
->srcreg(This
, &instr
->src
[i
], buffer
);
165 /* The length of an instruction consists of the destination register (if any),
166 * the number of source registers, the number of address registers used for
167 * indirect addressing, and optionally the predicate register
169 static DWORD
instrlen(const struct instruction
*instr
, unsigned int srcs
, unsigned int dsts
) {
171 DWORD ret
= srcs
+ dsts
+ (instr
->has_predicate
? 1 : 0);
174 if(instr
->dst
.rel_reg
) ret
++;
176 for(i
= 0; i
< srcs
; i
++) {
177 if(instr
->src
[i
].rel_reg
) ret
++;
182 static void instr_handler(struct bc_writer
*This
,
183 const struct instruction
*instr
,
184 struct bytecode_buffer
*buffer
) {
185 DWORD token
= d3d9_opcode(instr
->opcode
);
186 TRACE("token: %x\n", token
);
188 This
->funcs
->opcode(This
, instr
, token
, buffer
);
189 if(instr
->has_dst
) This
->funcs
->dstreg(This
, &instr
->dst
, buffer
, instr
->shift
, instr
->dstmod
);
190 write_srcregs(This
, instr
, buffer
);
193 static void sm_2_opcode(struct bc_writer
*This
,
194 const struct instruction
*instr
,
195 DWORD token
, struct bytecode_buffer
*buffer
) {
196 /* From sm 2 onwards instruction length is encoded in the opcode field */
197 int dsts
= instr
->has_dst
? 1 : 0;
198 token
|= instrlen(instr
, instr
->num_srcs
, dsts
) << D3DSI_INSTLENGTH_SHIFT
;
199 put_dword(buffer
,token
);
202 static void sm_3_header(struct bc_writer
*This
, const struct bwriter_shader
*shader
, struct bytecode_buffer
*buffer
) {
203 /* Declare the shader type and version */
204 put_dword(buffer
, This
->version
);
208 static void sm_3_srcreg(struct bc_writer
*This
,
209 const struct shader_reg
*reg
,
210 struct bytecode_buffer
*buffer
) {
211 DWORD token
= (1 << 31); /* Bit 31 of registers is 1 */
214 d3d9reg
= d3d9_register(reg
->type
);
215 token
|= (d3d9reg
<< D3DSP_REGTYPE_SHIFT
) & D3DSP_REGTYPE_MASK
;
216 token
|= (d3d9reg
<< D3DSP_REGTYPE_SHIFT2
) & D3DSP_REGTYPE_MASK2
;
217 token
|= reg
->regnum
& D3DSP_REGNUM_MASK
;
219 token
|= d3d9_swizzle(reg
->swizzle
) & D3DVS_SWIZZLE_MASK
;
221 put_dword(buffer
, token
);
224 static void sm_3_dstreg(struct bc_writer
*This
,
225 const struct shader_reg
*reg
,
226 struct bytecode_buffer
*buffer
,
227 DWORD shift
, DWORD mod
) {
228 DWORD token
= (1 << 31); /* Bit 31 of registers is 1 */
231 d3d9reg
= d3d9_register(reg
->type
);
232 token
|= (d3d9reg
<< D3DSP_REGTYPE_SHIFT
) & D3DSP_REGTYPE_MASK
;
233 token
|= (d3d9reg
<< D3DSP_REGTYPE_SHIFT2
) & D3DSP_REGTYPE_MASK2
;
234 token
|= reg
->regnum
& D3DSP_REGNUM_MASK
; /* No shift */
236 token
|= d3d9_writemask(reg
->writemask
);
237 put_dword(buffer
, token
);
240 static const struct instr_handler_table vs_3_handlers
[] = {
241 {BWRITERSIO_MOV
, instr_handler
},
242 {BWRITERSIO_END
, NULL
},
245 static const struct bytecode_backend vs_3_backend
= {
254 static void init_vs30_dx9_writer(struct bc_writer
*writer
) {
255 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
256 writer
->funcs
= &vs_3_backend
;
259 static struct bc_writer
*create_writer(DWORD version
, DWORD dxversion
) {
260 struct bc_writer
*ret
= asm_alloc(sizeof(*ret
));
263 WARN("Failed to allocate a bytecode writer instance\n");
268 case BWRITERVS_VERSION(1, 0):
270 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion
);
273 /* TODO: Set the appropriate writer backend */
275 case BWRITERVS_VERSION(1, 1):
277 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion
);
280 /* TODO: Set the appropriate writer backend */
282 case BWRITERVS_VERSION(2, 0):
284 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion
);
287 /* TODO: Set the appropriate writer backend */
289 case BWRITERVS_VERSION(2, 1):
291 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion
);
294 /* TODO: Set the appropriate writer backend */
296 case BWRITERVS_VERSION(3, 0):
298 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion
);
301 init_vs30_dx9_writer(ret
);
304 case BWRITERPS_VERSION(1, 0):
306 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion
);
309 /* TODO: Set the appropriate writer backend */
311 case BWRITERPS_VERSION(1, 1):
313 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion
);
316 /* TODO: Set the appropriate writer backend */
318 case BWRITERPS_VERSION(1, 2):
320 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion
);
323 /* TODO: Set the appropriate writer backend */
325 case BWRITERPS_VERSION(1, 3):
327 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion
);
330 /* TODO: Set the appropriate writer backend */
332 case BWRITERPS_VERSION(1, 4):
334 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion
);
337 /* TODO: Set the appropriate writer backend */
340 case BWRITERPS_VERSION(2, 0):
342 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion
);
345 /* TODO: Set the appropriate writer backend */
348 case BWRITERPS_VERSION(2, 1):
350 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion
);
353 /* TODO: Set the appropriate writer backend */
356 case BWRITERPS_VERSION(3, 0):
358 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion
);
361 /* TODO: Set the appropriate writer backend */
365 WARN("Unexpected shader version requested: %08x\n", version
);
368 ret
->version
= version
;
376 static HRESULT
call_instr_handler(struct bc_writer
*writer
,
377 const struct instruction
*instr
,
378 struct bytecode_buffer
*buffer
) {
381 while(writer
->funcs
->instructions
[i
].opcode
!= BWRITERSIO_END
) {
382 if(instr
->opcode
== writer
->funcs
->instructions
[i
].opcode
) {
383 if(!writer
->funcs
->instructions
[i
].func
) {
384 WARN("Opcode %u not supported by this profile\n", instr
->opcode
);
387 writer
->funcs
->instructions
[i
].func(writer
, instr
, buffer
);
393 FIXME("Unhandled instruction %u\n", instr
->opcode
);
397 /* SlWriteBytecode (wineshader.@)
399 * Writes shader version specific bytecode from the shader passed in.
400 * The returned bytecode can be passed to the Direct3D runtime like
401 * IDirect3DDevice9::Create*Shader.
404 * shader: Shader to translate into bytecode
405 * version: Shader version to generate(d3d version token)
406 * dxversion: DirectX version the code targets
407 * result: the resulting shader bytecode
412 DWORD
SlWriteBytecode(const struct bwriter_shader
*shader
, int dxversion
, DWORD
**result
) {
413 struct bc_writer
*writer
;
414 struct bytecode_buffer
*buffer
= NULL
;
419 ERR("NULL shader structure, aborting\n");
422 writer
= create_writer(shader
->version
, dxversion
);
426 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
427 WARN("or out of memory\n");
432 buffer
= allocate_buffer();
434 WARN("Failed to allocate a buffer for the shader bytecode\n");
439 writer
->funcs
->header(writer
, shader
, buffer
);
440 if(FAILED(writer
->state
)) {
445 for(i
= 0; i
< shader
->num_instrs
; i
++) {
446 hr
= call_instr_handler(writer
, shader
->instr
[i
], buffer
);
452 if(FAILED(writer
->state
)) {
457 writer
->funcs
->end(writer
, shader
, buffer
);
459 if(FAILED(buffer
->state
)) {
464 /* Cut off unneeded memory from the result buffer */
465 *result
= asm_realloc(buffer
->data
,
466 sizeof(DWORD
) * buffer
->size
);
468 *result
= buffer
->data
;
475 asm_free(buffer
->data
);
482 void SlDeleteShader(struct bwriter_shader
*shader
) {
485 TRACE("Deleting shader %p\n", shader
);
487 for(i
= 0; i
< shader
->num_cf
; i
++) {
488 asm_free(shader
->constF
[i
]);
490 asm_free(shader
->constF
);
491 for(i
= 0; i
< shader
->num_ci
; i
++) {
492 asm_free(shader
->constI
[i
]);
494 asm_free(shader
->constI
);
495 for(i
= 0; i
< shader
->num_cb
; i
++) {
496 asm_free(shader
->constB
[i
]);
498 asm_free(shader
->constB
);
500 asm_free(shader
->inputs
);
501 asm_free(shader
->outputs
);
502 asm_free(shader
->samplers
);
504 for(i
= 0; i
< shader
->num_instrs
; i
++) {
505 for(j
= 0; j
< shader
->instr
[i
]->num_srcs
; j
++) {
506 asm_free(shader
->instr
[i
]->src
[j
].rel_reg
);
508 asm_free(shader
->instr
[i
]->src
);
509 asm_free(shader
->instr
[i
]);
511 asm_free(shader
->instr
);