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;
200 token |= (d3d9_comparetype(instr->comptype) << 16) & (0xf << 16);
201 put_dword(buffer,token);
204 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
205 /* Declare the shader type and version */
206 put_dword(buffer, This->version);
210 static void sm_3_srcreg(struct bc_writer *This,
211 const struct shader_reg *reg,
212 struct bytecode_buffer *buffer) {
213 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
216 d3d9reg = d3d9_register(reg->type);
217 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
218 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
219 token |= reg->regnum & D3DSP_REGNUM_MASK;
221 token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK;
222 token |= d3d9_srcmod(reg->srcmod);
225 if(reg->type == BWRITERSPR_CONST && This->version == BWRITERPS_VERSION(3, 0)) {
226 WARN("c%u[...] is unsupported in ps_3_0\n", reg->regnum);
227 This->state = E_INVALIDARG;
230 if(((reg->rel_reg->type == BWRITERSPR_ADDR && This->version == BWRITERVS_VERSION(3, 0)) ||
231 reg->rel_reg->type == BWRITERSPR_LOOP) &&
232 reg->rel_reg->regnum == 0) {
233 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
235 WARN("Unsupported relative addressing register\n");
236 This->state = E_INVALIDARG;
241 put_dword(buffer, token);
243 /* vs_2_0 and newer write the register containing the index explicitly in the
246 if(token & D3DVS_ADDRMODE_RELATIVE) {
247 sm_3_srcreg(This, reg->rel_reg, buffer);
251 static void sm_3_dstreg(struct bc_writer *This,
252 const struct shader_reg *reg,
253 struct bytecode_buffer *buffer,
254 DWORD shift, DWORD mod) {
255 DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
259 if(This->version == BWRITERVS_VERSION(3, 0) &&
260 reg->type == BWRITERSPR_OUTPUT) {
261 token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
263 WARN("Relative addressing not supported for this shader type or register type\n");
264 This->state = E_INVALIDARG;
269 d3d9reg = d3d9_register(reg->type);
270 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
271 token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
272 token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
274 token |= d3d9_dstmod(mod);
276 token |= d3d9_writemask(reg->writemask);
277 put_dword(buffer, token);
279 /* vs_2_0 and newer write the register containing the index explicitly in the
282 if(token & D3DVS_ADDRMODE_RELATIVE) {
283 sm_3_srcreg(This, reg->rel_reg, buffer);
287 static const struct instr_handler_table vs_3_handlers[] = {
288 {BWRITERSIO_ADD, instr_handler},
289 {BWRITERSIO_NOP, instr_handler},
290 {BWRITERSIO_MOV, instr_handler},
291 {BWRITERSIO_SUB, instr_handler},
292 {BWRITERSIO_MAD, instr_handler},
293 {BWRITERSIO_MUL, instr_handler},
294 {BWRITERSIO_RCP, instr_handler},
295 {BWRITERSIO_RSQ, instr_handler},
296 {BWRITERSIO_DP3, instr_handler},
297 {BWRITERSIO_DP4, instr_handler},
298 {BWRITERSIO_MIN, instr_handler},
299 {BWRITERSIO_MAX, instr_handler},
300 {BWRITERSIO_SLT, instr_handler},
301 {BWRITERSIO_SGE, instr_handler},
302 {BWRITERSIO_ABS, instr_handler},
303 {BWRITERSIO_EXP, instr_handler},
304 {BWRITERSIO_LOG, instr_handler},
305 {BWRITERSIO_EXPP, instr_handler},
306 {BWRITERSIO_LOGP, instr_handler},
307 {BWRITERSIO_DST, instr_handler},
308 {BWRITERSIO_LRP, instr_handler},
309 {BWRITERSIO_FRC, instr_handler},
310 {BWRITERSIO_CRS, instr_handler},
311 {BWRITERSIO_SGN, instr_handler},
312 {BWRITERSIO_NRM, instr_handler},
313 {BWRITERSIO_SINCOS, instr_handler},
314 {BWRITERSIO_M4x4, instr_handler},
315 {BWRITERSIO_M4x3, instr_handler},
316 {BWRITERSIO_M3x4, instr_handler},
317 {BWRITERSIO_M3x3, instr_handler},
318 {BWRITERSIO_M3x2, instr_handler},
319 {BWRITERSIO_LIT, instr_handler},
320 {BWRITERSIO_POW, instr_handler},
321 {BWRITERSIO_MOVA, instr_handler},
323 {BWRITERSIO_CALL, instr_handler},
324 {BWRITERSIO_CALLNZ, instr_handler},
325 {BWRITERSIO_REP, instr_handler},
326 {BWRITERSIO_ENDREP, instr_handler},
327 {BWRITERSIO_IF, instr_handler},
328 {BWRITERSIO_LABEL, instr_handler},
329 {BWRITERSIO_IFC, instr_handler},
330 {BWRITERSIO_ELSE, instr_handler},
331 {BWRITERSIO_ENDIF, instr_handler},
332 {BWRITERSIO_BREAK, instr_handler},
333 {BWRITERSIO_BREAKC, instr_handler},
334 {BWRITERSIO_LOOP, instr_handler},
335 {BWRITERSIO_RET, instr_handler},
336 {BWRITERSIO_ENDLOOP, instr_handler},
338 {BWRITERSIO_TEXLDL, instr_handler},
340 {BWRITERSIO_END, NULL},
343 static const struct bytecode_backend vs_3_backend = {
352 static void init_vs30_dx9_writer(struct bc_writer *writer) {
353 TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
354 writer->funcs = &vs_3_backend;
357 static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
358 struct bc_writer *ret = asm_alloc(sizeof(*ret));
361 WARN("Failed to allocate a bytecode writer instance\n");
366 case BWRITERVS_VERSION(1, 0):
368 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
371 /* TODO: Set the appropriate writer backend */
373 case BWRITERVS_VERSION(1, 1):
375 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
378 /* TODO: Set the appropriate writer backend */
380 case BWRITERVS_VERSION(2, 0):
382 WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
385 /* TODO: Set the appropriate writer backend */
387 case BWRITERVS_VERSION(2, 1):
389 WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
392 /* TODO: Set the appropriate writer backend */
394 case BWRITERVS_VERSION(3, 0):
396 WARN("Unsupported dxversion for vertex shader 3.0 requested: %u\n", dxversion);
399 init_vs30_dx9_writer(ret);
402 case BWRITERPS_VERSION(1, 0):
404 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
407 /* TODO: Set the appropriate writer backend */
409 case BWRITERPS_VERSION(1, 1):
411 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
414 /* TODO: Set the appropriate writer backend */
416 case BWRITERPS_VERSION(1, 2):
418 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
421 /* TODO: Set the appropriate writer backend */
423 case BWRITERPS_VERSION(1, 3):
425 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
428 /* TODO: Set the appropriate writer backend */
430 case BWRITERPS_VERSION(1, 4):
432 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
435 /* TODO: Set the appropriate writer backend */
438 case BWRITERPS_VERSION(2, 0):
440 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
443 /* TODO: Set the appropriate writer backend */
446 case BWRITERPS_VERSION(2, 1):
448 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
451 /* TODO: Set the appropriate writer backend */
454 case BWRITERPS_VERSION(3, 0):
456 WARN("Unsupported dxversion for pixel shader 3.0 requested: %u\n", dxversion);
459 /* TODO: Set the appropriate writer backend */
463 WARN("Unexpected shader version requested: %08x\n", version);
466 ret->version = version;
474 static HRESULT call_instr_handler(struct bc_writer *writer,
475 const struct instruction *instr,
476 struct bytecode_buffer *buffer) {
479 while(writer->funcs->instructions[i].opcode != BWRITERSIO_END) {
480 if(instr->opcode == writer->funcs->instructions[i].opcode) {
481 if(!writer->funcs->instructions[i].func) {
482 WARN("Opcode %u not supported by this profile\n", instr->opcode);
485 writer->funcs->instructions[i].func(writer, instr, buffer);
491 FIXME("Unhandled instruction %u\n", instr->opcode);
495 /* SlWriteBytecode (wineshader.@)
497 * Writes shader version specific bytecode from the shader passed in.
498 * The returned bytecode can be passed to the Direct3D runtime like
499 * IDirect3DDevice9::Create*Shader.
502 * shader: Shader to translate into bytecode
503 * version: Shader version to generate(d3d version token)
504 * dxversion: DirectX version the code targets
505 * result: the resulting shader bytecode
510 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result) {
511 struct bc_writer *writer;
512 struct bytecode_buffer *buffer = NULL;
517 ERR("NULL shader structure, aborting\n");
520 writer = create_writer(shader->version, dxversion);
524 WARN("Could not create a bytecode writer instance. Either unsupported version\n");
525 WARN("or out of memory\n");
530 buffer = allocate_buffer();
532 WARN("Failed to allocate a buffer for the shader bytecode\n");
537 writer->funcs->header(writer, shader, buffer);
538 if(FAILED(writer->state)) {
543 for(i = 0; i < shader->num_instrs; i++) {
544 hr = call_instr_handler(writer, shader->instr[i], buffer);
550 if(FAILED(writer->state)) {
555 writer->funcs->end(writer, shader, buffer);
557 if(FAILED(buffer->state)) {
562 /* Cut off unneeded memory from the result buffer */
563 *result = asm_realloc(buffer->data,
564 sizeof(DWORD) * buffer->size);
566 *result = buffer->data;
573 asm_free(buffer->data);
580 void SlDeleteShader(struct bwriter_shader *shader) {
583 TRACE("Deleting shader %p\n", shader);
585 for(i = 0; i < shader->num_cf; i++) {
586 asm_free(shader->constF[i]);
588 asm_free(shader->constF);
589 for(i = 0; i < shader->num_ci; i++) {
590 asm_free(shader->constI[i]);
592 asm_free(shader->constI);
593 for(i = 0; i < shader->num_cb; i++) {
594 asm_free(shader->constB[i]);
596 asm_free(shader->constB);
598 asm_free(shader->inputs);
599 asm_free(shader->outputs);
600 asm_free(shader->samplers);
602 for(i = 0; i < shader->num_instrs; i++) {
603 for(j = 0; j < shader->instr[i]->num_srcs; j++) {
604 asm_free(shader->instr[i]->src[j].rel_reg);
606 asm_free(shader->instr[i]->src);
607 asm_free(shader->instr[i]);
609 asm_free(shader->instr);