This is in preparation of sharing the fragment program compiler with Gallium: Compiler code is moved into its own directory and modified so that it no longer depends on driver structures. Signed-off-by: Nicolai Hähnle <nhaehnle@gmail.com>tags/mesa_7_6_rc1
@@ -38,6 +38,18 @@ RADEON_COMMON_SOURCES = \ | |||
radeon_span.c \ | |||
radeon_fbo.c | |||
RADEON_COMPILER_SOURCES = \ | |||
compiler/radeon_nqssadce.c \ | |||
compiler/radeon_program.c \ | |||
compiler/radeon_program_alu.c \ | |||
compiler/radeon_program_pair.c \ | |||
compiler/r3xx_fragprog.c \ | |||
compiler/r300_fragprog.c \ | |||
compiler/r300_fragprog_swizzle.c \ | |||
compiler/r300_fragprog_emit.c \ | |||
compiler/r500_fragprog.c \ | |||
compiler/r500_fragprog_emit.c \ | |||
DRIVER_SOURCES = \ | |||
radeon_screen.c \ | |||
r300_context.c \ | |||
@@ -48,21 +60,13 @@ DRIVER_SOURCES = \ | |||
r300_render.c \ | |||
r300_tex.c \ | |||
r300_texstate.c \ | |||
radeon_program.c \ | |||
radeon_program_alu.c \ | |||
radeon_program_pair.c \ | |||
radeon_nqssadce.c \ | |||
r300_vertprog.c \ | |||
r300_fragprog_common.c \ | |||
r300_fragprog.c \ | |||
r300_fragprog_swizzle.c \ | |||
r300_fragprog_emit.c \ | |||
r500_fragprog.c \ | |||
r500_fragprog_emit.c \ | |||
r300_shader.c \ | |||
r300_emit.c \ | |||
r300_swtcl.c \ | |||
$(RADEON_COMMON_SOURCES) \ | |||
$(RADEON_COMPILER_SOURCES) \ | |||
$(EGL_SOURCES) \ | |||
$(CS_SOURCES) | |||
@@ -25,12 +25,11 @@ | |||
* | |||
*/ | |||
#include "r300_fragprog.h" | |||
#include "compiler/r300_fragprog.h" | |||
#include "shader/prog_parameter.h" | |||
#include "r300_context.h" | |||
#include "r300_fragprog_swizzle.h" | |||
#include "r300_reg.h" | |||
static void reset_srcreg(struct prog_src_register* reg) | |||
{ | |||
@@ -79,7 +78,7 @@ GLboolean r300_transform_TEX( | |||
if (inst.Opcode != OPCODE_KIL && | |||
t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) { | |||
GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint comparefunc = GL_NEVER + compiler->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
if (comparefunc == GL_NEVER || comparefunc == GL_ALWAYS) { | |||
tgt = radeonAppendInstructions(t->Program, 1); | |||
@@ -163,8 +162,8 @@ GLboolean r300_transform_TEX( | |||
if (inst.Opcode != OPCODE_KIL && | |||
t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) { | |||
GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint depthmode = compiler->fp->state.unit[inst.TexSrcUnit].depth_texture_mode; | |||
GLuint comparefunc = GL_NEVER + compiler->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint depthmode = compiler->state.unit[inst.TexSrcUnit].depth_texture_mode; | |||
int rcptemp = radeonFindFreeTemporary(t); | |||
int pass, fail; | |||
@@ -230,9 +229,9 @@ GLboolean r300_transform_TEX( | |||
} | |||
/* just some random things... */ | |||
void r300FragmentProgramDump(union rX00_fragment_program_code *c) | |||
void r300FragmentProgramDump(struct rX00_fragment_program_code *c) | |||
{ | |||
struct r300_fragment_program_code *code = &c->r300; | |||
struct r300_fragment_program_code *code = &c->code.r300; | |||
int n, i, j; | |||
static int pc = 0; | |||
@@ -0,0 +1,49 @@ | |||
/* | |||
* Copyright (C) 2005 Ben Skeggs. | |||
* | |||
* All Rights Reserved. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sublicense, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the | |||
* next paragraph) shall be included in all copies or substantial | |||
* portions of the Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | |||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
*/ | |||
/* | |||
* Authors: | |||
* Ben Skeggs <darktama@iinet.net.au> | |||
* Jerome Glisse <j.glisse@gmail.com> | |||
*/ | |||
#ifndef __R300_FRAGPROG_H_ | |||
#define __R300_FRAGPROG_H_ | |||
#include "shader/program.h" | |||
#include "shader/prog_instruction.h" | |||
#include "compiler/radeon_compiler.h" | |||
#include "compiler/radeon_program.h" | |||
extern GLboolean r300BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler); | |||
extern void r300FragmentProgramDump(struct rX00_fragment_program_code *c); | |||
extern GLboolean r300_transform_TEX(struct radeon_transform_context *t, struct prog_instruction* orig_inst, void* data); | |||
#endif |
@@ -38,16 +38,17 @@ | |||
* \todo FogOption | |||
*/ | |||
#include "r300_fragprog.h" | |||
#include "compiler/r300_fragprog.h" | |||
#include "radeon_program_pair.h" | |||
#include "r300_fragprog_swizzle.h" | |||
#include "r300_reg.h" | |||
#include "compiler/radeon_program_pair.h" | |||
#include "compiler/r300_fragprog_swizzle.h" | |||
#define PROG_CODE \ | |||
struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)data; \ | |||
struct r300_fragment_program_code *code = &c->code->r300 | |||
struct r300_fragment_program_code *code = &c->code->code.r300 | |||
#define error(fmt, args...) do { \ | |||
fprintf(stderr, "%s::%s(): " fmt "\n", \ | |||
@@ -201,7 +202,7 @@ static GLboolean emit_alu(void* data, struct radeon_pair_instruction* inst) | |||
if (inst->Alpha.DepthWriteMask) { | |||
code->alu.inst[ip].inst3 |= R300_ALU_DSTA_DEPTH; | |||
code->node[code->cur_node].flags |= R300_W_OUT; | |||
c->fp->writes_depth = GL_TRUE; | |||
c->code->writes_depth = GL_TRUE; | |||
} | |||
return GL_TRUE; | |||
@@ -213,7 +214,7 @@ static GLboolean emit_alu(void* data, struct radeon_pair_instruction* inst) | |||
*/ | |||
static GLboolean finish_node(struct r300_fragment_program_compiler *c) | |||
{ | |||
struct r300_fragment_program_code *code = &c->code->r300; | |||
struct r300_fragment_program_code *code = &c->code->code.r300; | |||
struct r300_fragment_program_node *node = &code->node[code->cur_node]; | |||
if (node->alu_end < 0) { | |||
@@ -327,13 +328,13 @@ static const struct radeon_pair_handler pair_handler = { | |||
*/ | |||
GLboolean r300BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
struct r300_fragment_program_code *code = &compiler->code->r300; | |||
struct r300_fragment_program_code *code = &compiler->code->code.r300; | |||
_mesa_bzero(code, sizeof(struct r300_fragment_program_code)); | |||
code->node[0].alu_end = -1; | |||
code->node[0].tex_end = -1; | |||
if (!radeonPairProgram(compiler->r300->radeon.glCtx, compiler->program, &pair_handler, compiler)) | |||
if (!radeonPairProgram(compiler->ctx, compiler->program, &pair_handler, compiler)) | |||
return GL_FALSE; | |||
if (!finish_node(compiler)) |
@@ -0,0 +1,315 @@ | |||
/* | |||
* Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com> | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a | |||
* copy of this software and associated documentation files (the "Software"), | |||
* to deal in the Software without restriction, including without limitation | |||
* on the rights to use, copy, modify, merge, publish, distribute, sub | |||
* license, and/or sell copies of the Software, and to permit persons to whom | |||
* the Software is furnished to do so, subject to the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the next | |||
* paragraph) shall be included in all copies or substantial portions of the | |||
* Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | |||
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, | |||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |||
* USE OR OTHER DEALINGS IN THE SOFTWARE. */ | |||
#include "radeon_compiler.h" | |||
#include "shader/prog_parameter.h" | |||
#include "shader/prog_print.h" | |||
#include "shader/prog_statevars.h" | |||
#include "radeon_nqssadce.h" | |||
#include "radeon_program_alu.h" | |||
#include "r300_fragprog.h" | |||
#include "r300_fragprog_swizzle.h" | |||
#include "r500_fragprog.h" | |||
static void nqssadce_init(struct nqssadce_state* s) | |||
{ | |||
s->Outputs[FRAG_RESULT_COLOR].Sourced = WRITEMASK_XYZW; | |||
s->Outputs[FRAG_RESULT_DEPTH].Sourced = WRITEMASK_W; | |||
} | |||
/** | |||
* Transform the program to support fragment.position. | |||
* | |||
* Introduce a small fragment at the start of the program that will be | |||
* the only code that directly reads the FRAG_ATTRIB_WPOS input. | |||
* All other code pieces that reference that input will be rewritten | |||
* to read from a newly allocated temporary. | |||
* | |||
*/ | |||
static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
GLuint InputsRead = compiler->program->InputsRead; | |||
if (!(InputsRead & FRAG_BIT_WPOS)) { | |||
compiler->code->wpos_attr = FRAG_ATTRIB_MAX; | |||
return; | |||
} | |||
static gl_state_index tokens[STATE_LENGTH] = { | |||
STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0 | |||
}; | |||
struct prog_instruction *fpi; | |||
GLuint window_index; | |||
int i = 0; | |||
for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i) | |||
{ | |||
if (!(InputsRead & (1 << i))) { | |||
InputsRead &= ~(1 << FRAG_ATTRIB_WPOS); | |||
InputsRead |= 1 << i; | |||
compiler->program->InputsRead = InputsRead; | |||
compiler->code->wpos_attr = i; | |||
break; | |||
} | |||
} | |||
GLuint tempregi = _mesa_find_free_register(compiler->program, PROGRAM_TEMPORARY); | |||
_mesa_insert_instructions(compiler->program, 0, 3); | |||
fpi = compiler->program->Instructions; | |||
i = 0; | |||
/* perspective divide */ | |||
fpi[i].Opcode = OPCODE_RCP; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_W; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_INPUT; | |||
fpi[i].SrcReg[0].Index = compiler->code->wpos_attr; | |||
fpi[i].SrcReg[0].Swizzle = SWIZZLE_WWWW; | |||
i++; | |||
fpi[i].Opcode = OPCODE_MUL; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_XYZ; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_INPUT; | |||
fpi[i].SrcReg[0].Index = compiler->code->wpos_attr; | |||
fpi[i].SrcReg[0].Swizzle = SWIZZLE_XYZW; | |||
fpi[i].SrcReg[1].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[1].Index = tempregi; | |||
fpi[i].SrcReg[1].Swizzle = SWIZZLE_WWWW; | |||
i++; | |||
/* viewport transformation */ | |||
window_index = _mesa_add_state_reference(compiler->program->Parameters, tokens); | |||
fpi[i].Opcode = OPCODE_MAD; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_XYZ; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[0].Index = tempregi; | |||
fpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
fpi[i].SrcReg[1].File = PROGRAM_STATE_VAR; | |||
fpi[i].SrcReg[1].Index = window_index; | |||
fpi[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
fpi[i].SrcReg[2].File = PROGRAM_STATE_VAR; | |||
fpi[i].SrcReg[2].Index = window_index; | |||
fpi[i].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
i++; | |||
for (; i < compiler->program->NumInstructions; ++i) { | |||
int reg; | |||
for (reg = 0; reg < 3; reg++) { | |||
if (fpi[i].SrcReg[reg].File == PROGRAM_INPUT && | |||
fpi[i].SrcReg[reg].Index == FRAG_ATTRIB_WPOS) { | |||
fpi[i].SrcReg[reg].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[reg].Index = tempregi; | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Rewrite fragment.fogcoord to use a texture coordinate slot. | |||
* Note that fogcoord is forced into an X001 pattern, and this enforcement | |||
* is done here. | |||
* | |||
* See also the counterpart rewriting for vertex programs. | |||
*/ | |||
static void rewriteFog(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
struct rX00_fragment_program_code *code = compiler->code; | |||
GLuint InputsRead = compiler->program->InputsRead; | |||
int i; | |||
if (!(InputsRead & FRAG_BIT_FOGC)) { | |||
code->fog_attr = FRAG_ATTRIB_MAX; | |||
return; | |||
} | |||
for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i) | |||
{ | |||
if (!(InputsRead & (1 << i))) { | |||
InputsRead &= ~(1 << FRAG_ATTRIB_FOGC); | |||
InputsRead |= 1 << i; | |||
compiler->program->InputsRead = InputsRead; | |||
code->fog_attr = i; | |||
break; | |||
} | |||
} | |||
{ | |||
struct prog_instruction *inst; | |||
inst = compiler->program->Instructions; | |||
while (inst->Opcode != OPCODE_END) { | |||
const int src_regs = _mesa_num_inst_src_regs(inst->Opcode); | |||
for (i = 0; i < src_regs; ++i) { | |||
if (inst->SrcReg[i].File == PROGRAM_INPUT && inst->SrcReg[i].Index == FRAG_ATTRIB_FOGC) { | |||
inst->SrcReg[i].Index = code->fog_attr; | |||
inst->SrcReg[i].Swizzle = combine_swizzles( | |||
MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), | |||
inst->SrcReg[i].Swizzle); | |||
} | |||
} | |||
++inst; | |||
} | |||
} | |||
} | |||
static void rewrite_depth_out(struct gl_program *prog) | |||
{ | |||
struct prog_instruction *inst; | |||
for (inst = prog->Instructions; inst->Opcode != OPCODE_END; ++inst) { | |||
if (inst->DstReg.File != PROGRAM_OUTPUT || inst->DstReg.Index != FRAG_RESULT_DEPTH) | |||
continue; | |||
if (inst->DstReg.WriteMask & WRITEMASK_Z) { | |||
inst->DstReg.WriteMask = WRITEMASK_W; | |||
} else { | |||
inst->DstReg.WriteMask = 0; | |||
continue; | |||
} | |||
switch (inst->Opcode) { | |||
case OPCODE_FRC: | |||
case OPCODE_MOV: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
break; | |||
case OPCODE_ADD: | |||
case OPCODE_MAX: | |||
case OPCODE_MIN: | |||
case OPCODE_MUL: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]); | |||
break; | |||
case OPCODE_CMP: | |||
case OPCODE_MAD: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]); | |||
inst->SrcReg[2] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[2]); | |||
break; | |||
default: | |||
// Scalar instructions needn't be reswizzled | |||
break; | |||
} | |||
} | |||
} | |||
GLboolean r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) | |||
{ | |||
GLboolean success = GL_FALSE; | |||
if (c->debug) { | |||
fflush(stdout); | |||
_mesa_printf("Fragment Program: Initial program:\n"); | |||
_mesa_print_program(c->program); | |||
fflush(stdout); | |||
} | |||
insert_WPOS_trailer(c); | |||
rewriteFog(c); | |||
rewrite_depth_out(c->program); | |||
if (c->is_r500) { | |||
struct radeon_program_transformation transformations[] = { | |||
{ &r500_transform_TEX, c }, | |||
{ &radeonTransformALU, 0 }, | |||
{ &radeonTransformDeriv, 0 }, | |||
{ &radeonTransformTrigScale, 0 } | |||
}; | |||
radeonLocalTransform(c->ctx, c->program, 4, transformations); | |||
} else { | |||
struct radeon_program_transformation transformations[] = { | |||
{ &r300_transform_TEX, c }, | |||
{ &radeonTransformALU, 0 }, | |||
{ &radeonTransformTrigSimple, 0 } | |||
}; | |||
radeonLocalTransform(c->ctx, c->program, 3, transformations); | |||
} | |||
if (c->debug) { | |||
_mesa_printf("Fragment Program: After native rewrite:\n"); | |||
_mesa_print_program(c->program); | |||
fflush(stdout); | |||
} | |||
if (c->is_r500) { | |||
struct radeon_nqssadce_descr nqssadce = { | |||
.Init = &nqssadce_init, | |||
.IsNativeSwizzle = &r500FPIsNativeSwizzle, | |||
.BuildSwizzle = &r500FPBuildSwizzle | |||
}; | |||
radeonNqssaDce(c->ctx, c->program, &nqssadce); | |||
} else { | |||
struct radeon_nqssadce_descr nqssadce = { | |||
.Init = &nqssadce_init, | |||
.IsNativeSwizzle = &r300FPIsNativeSwizzle, | |||
.BuildSwizzle = &r300FPBuildSwizzle | |||
}; | |||
radeonNqssaDce(c->ctx, c->program, &nqssadce); | |||
} | |||
if (c->debug) { | |||
_mesa_printf("Compiler: after NqSSA-DCE:\n"); | |||
_mesa_print_program(c->program); | |||
fflush(stdout); | |||
} | |||
if (c->is_r500) { | |||
success = r500BuildFragmentProgramHwCode(c); | |||
} else { | |||
success = r300BuildFragmentProgramHwCode(c); | |||
} | |||
if (!success || c->debug) { | |||
if (c->is_r500) { | |||
r500FragmentProgramDump(c->code); | |||
} else { | |||
r300FragmentProgramDump(c->code); | |||
} | |||
} | |||
return success; | |||
} |
@@ -25,7 +25,9 @@ | |||
* | |||
*/ | |||
#include "r500_fragprog.h" | |||
#include "compiler/r500_fragprog.h" | |||
#include "r300_reg.h" | |||
static void reset_srcreg(struct prog_src_register* reg) | |||
{ | |||
@@ -73,7 +75,7 @@ GLboolean r500_transform_TEX( | |||
/* ARB_shadow & EXT_shadow_funcs */ | |||
if (inst.Opcode != OPCODE_KIL && | |||
t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) { | |||
GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint comparefunc = GL_NEVER + compiler->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
if (comparefunc == GL_NEVER || comparefunc == GL_ALWAYS) { | |||
tgt = radeonAppendInstructions(t->Program, 1); | |||
@@ -119,8 +121,8 @@ GLboolean r500_transform_TEX( | |||
if (inst.Opcode != OPCODE_KIL && | |||
t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) { | |||
GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint depthmode = compiler->fp->state.unit[inst.TexSrcUnit].depth_texture_mode; | |||
GLuint comparefunc = GL_NEVER + compiler->state.unit[inst.TexSrcUnit].texture_compare_func; | |||
GLuint depthmode = compiler->state.unit[inst.TexSrcUnit].depth_texture_mode; | |||
int rcptemp = radeonFindFreeTemporary(t); | |||
int pass, fail; | |||
@@ -375,9 +377,9 @@ static char *to_texop(int val) | |||
return NULL; | |||
} | |||
void r500FragmentProgramDump(union rX00_fragment_program_code *c) | |||
void r500FragmentProgramDump(struct rX00_fragment_program_code *c) | |||
{ | |||
struct r500_fragment_program_code *code = &c->r500; | |||
struct r500_fragment_program_code *code = &c->code.r500; | |||
fprintf(stderr, "R500 Fragment Program:\n--------\n"); | |||
int n; |
@@ -36,12 +36,12 @@ | |||
#include "shader/prog_parameter.h" | |||
#include "shader/prog_instruction.h" | |||
#include "r300_context.h" | |||
#include "radeon_nqssadce.h" | |||
#include "compiler/radeon_compiler.h" | |||
#include "compiler/radeon_nqssadce.h" | |||
extern GLboolean r500BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler); | |||
extern void r500FragmentProgramDump(union rX00_fragment_program_code *c); | |||
extern void r500FragmentProgramDump(struct rX00_fragment_program_code *c); | |||
extern GLboolean r500FPIsNativeSwizzle(GLuint opcode, struct prog_src_register reg); | |||
@@ -43,14 +43,16 @@ | |||
* | |||
*/ | |||
#include "r500_fragprog.h" | |||
#include "compiler/r500_fragprog.h" | |||
#include "radeon_program_pair.h" | |||
#include "r300_reg.h" | |||
#include "compiler/radeon_program_pair.h" | |||
#define PROG_CODE \ | |||
struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)data; \ | |||
struct r500_fragment_program_code *code = &c->code->r500 | |||
struct r500_fragment_program_code *code = &c->code->code.r500 | |||
#define error(fmt, args...) do { \ | |||
fprintf(stderr, "%s::%s(): " fmt "\n", \ | |||
@@ -202,7 +204,7 @@ static GLboolean emit_paired(void *data, struct radeon_pair_instruction *inst) | |||
code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18); | |||
if (inst->Alpha.DepthWriteMask) { | |||
code->inst[ip].inst4 |= R500_ALPHA_W_OMASK; | |||
c->fp->writes_depth = GL_TRUE; | |||
c->code->writes_depth = GL_TRUE; | |||
} | |||
code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex); | |||
@@ -301,14 +303,14 @@ static const struct radeon_pair_handler pair_handler = { | |||
GLboolean r500BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
struct r500_fragment_program_code *code = &compiler->code->r500; | |||
struct r500_fragment_program_code *code = &compiler->code->code.r500; | |||
_mesa_bzero(code, sizeof(*code)); | |||
code->max_temp_idx = 1; | |||
code->inst_offset = 0; | |||
code->inst_end = -1; | |||
if (!radeonPairProgram(compiler->r300->radeon.glCtx, compiler->program, &pair_handler, compiler)) | |||
if (!radeonPairProgram(compiler->ctx, compiler->program, &pair_handler, compiler)) | |||
return GL_FALSE; | |||
if ((code->inst[code->inst_end].inst0 & R500_INST_TYPE_MASK) != R500_INST_TYPE_OUT) { |
@@ -0,0 +1,162 @@ | |||
/* | |||
* Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com> | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a | |||
* copy of this software and associated documentation files (the "Software"), | |||
* to deal in the Software without restriction, including without limitation | |||
* on the rights to use, copy, modify, merge, publish, distribute, sub | |||
* license, and/or sell copies of the Software, and to permit persons to whom | |||
* the Software is furnished to do so, subject to the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the next | |||
* paragraph) shall be included in all copies or substantial portions of the | |||
* Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | |||
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, | |||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |||
* USE OR OTHER DEALINGS IN THE SOFTWARE. */ | |||
#ifndef RADEON_COMPILER_H | |||
#define RADEON_COMPILER_H | |||
#include "main/mtypes.h" | |||
#include "shader/prog_instruction.h" | |||
#define R300_PFS_MAX_ALU_INST 64 | |||
#define R300_PFS_MAX_TEX_INST 32 | |||
#define R300_PFS_MAX_TEX_INDIRECT 4 | |||
#define R300_PFS_NUM_TEMP_REGS 32 | |||
#define R300_PFS_NUM_CONST_REGS 32 | |||
#define R500_PFS_MAX_INST 512 | |||
#define R500_PFS_NUM_TEMP_REGS 128 | |||
#define R500_PFS_NUM_CONST_REGS 256 | |||
#define STATE_R300_WINDOW_DIMENSION (STATE_INTERNAL_DRIVER+0) | |||
#define STATE_R300_TEXRECT_FACTOR (STATE_INTERNAL_DRIVER+1) | |||
/** | |||
* Stores state that influences the compilation of a fragment program. | |||
*/ | |||
struct r300_fragment_program_external_state { | |||
struct { | |||
/** | |||
* If the sampler is used as a shadow sampler, | |||
* this field is: | |||
* 0 - GL_LUMINANCE | |||
* 1 - GL_INTENSITY | |||
* 2 - GL_ALPHA | |||
* depending on the depth texture mode. | |||
*/ | |||
GLuint depth_texture_mode : 2; | |||
/** | |||
* If the sampler is used as a shadow sampler, | |||
* this field is (texture_compare_func - GL_NEVER). | |||
* [e.g. if compare function is GL_LEQUAL, this field is 3] | |||
* | |||
* Otherwise, this field is 0. | |||
*/ | |||
GLuint texture_compare_func : 3; | |||
} unit[16]; | |||
}; | |||
struct r300_fragment_program_node { | |||
int tex_offset; /**< first tex instruction */ | |||
int tex_end; /**< last tex instruction, relative to tex_offset */ | |||
int alu_offset; /**< first ALU instruction */ | |||
int alu_end; /**< last ALU instruction, relative to alu_offset */ | |||
int flags; | |||
}; | |||
/** | |||
* Stores an R300 fragment program in its compiled-to-hardware form. | |||
*/ | |||
struct r300_fragment_program_code { | |||
struct { | |||
int length; /**< total # of texture instructions used */ | |||
GLuint inst[R300_PFS_MAX_TEX_INST]; | |||
} tex; | |||
struct { | |||
int length; /**< total # of ALU instructions used */ | |||
struct { | |||
GLuint inst0; | |||
GLuint inst1; | |||
GLuint inst2; | |||
GLuint inst3; | |||
} inst[R300_PFS_MAX_ALU_INST]; | |||
} alu; | |||
struct r300_fragment_program_node node[4]; | |||
int cur_node; | |||
int first_node_has_tex; | |||
/** | |||
* Remember which program register a given hardware constant | |||
* belongs to. | |||
*/ | |||
struct prog_src_register constant[R300_PFS_NUM_CONST_REGS]; | |||
int const_nr; | |||
int max_temp_idx; | |||
}; | |||
struct r500_fragment_program_code { | |||
struct { | |||
GLuint inst0; | |||
GLuint inst1; | |||
GLuint inst2; | |||
GLuint inst3; | |||
GLuint inst4; | |||
GLuint inst5; | |||
} inst[R500_PFS_MAX_INST]; | |||
int inst_offset; | |||
int inst_end; | |||
/** | |||
* Remember which program register a given hardware constant | |||
* belongs to. | |||
*/ | |||
struct prog_src_register constant[R500_PFS_NUM_CONST_REGS]; | |||
int const_nr; | |||
int max_temp_idx; | |||
}; | |||
struct rX00_fragment_program_code { | |||
union { | |||
struct r300_fragment_program_code r300; | |||
struct r500_fragment_program_code r500; | |||
} code; | |||
GLboolean writes_depth; | |||
/* attribute that we are sending the WPOS in */ | |||
gl_frag_attrib wpos_attr; | |||
/* attribute that we are sending the fog coordinate in */ | |||
gl_frag_attrib fog_attr; | |||
}; | |||
struct r300_fragment_program_compiler { | |||
GLcontext * ctx; | |||
struct rX00_fragment_program_code *code; | |||
struct gl_program *program; | |||
struct r300_fragment_program_external_state state; | |||
GLboolean is_r500; | |||
GLboolean debug; | |||
}; | |||
GLboolean r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c); | |||
#endif /* RADEON_COMPILER_H */ |
@@ -44,6 +44,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "main/mtypes.h" | |||
#include "shader/prog_instruction.h" | |||
#include "compiler/radeon_compiler.h" | |||
struct r300_context; | |||
typedef struct r300_context r300ContextRec; | |||
@@ -396,9 +397,6 @@ struct r300_hw_state { | |||
/* Can be tested with colormat currently. */ | |||
#define VSF_MAX_FRAGMENT_TEMPS (14) | |||
#define STATE_R300_WINDOW_DIMENSION (STATE_INTERNAL_DRIVER+0) | |||
#define STATE_R300_TEXRECT_FACTOR (STATE_INTERNAL_DRIVER+1) | |||
#define COLOR_IS_RGBA | |||
#define TAG(x) r300##x | |||
#include "tnl_dd/t_dd_vertex.h" | |||
@@ -413,7 +411,7 @@ struct r300_vertex_program { | |||
GLuint FogAttr; | |||
GLuint WPosAttr; | |||
} key; | |||
struct r300_vertex_shader_hw_code { | |||
int length; | |||
union { | |||
@@ -441,110 +439,6 @@ struct r300_vertex_program_cont { | |||
struct r300_vertex_program *progs; | |||
}; | |||
#define R300_PFS_MAX_ALU_INST 64 | |||
#define R300_PFS_MAX_TEX_INST 32 | |||
#define R300_PFS_MAX_TEX_INDIRECT 4 | |||
#define R300_PFS_NUM_TEMP_REGS 32 | |||
#define R300_PFS_NUM_CONST_REGS 32 | |||
#define R500_PFS_MAX_INST 512 | |||
#define R500_PFS_NUM_TEMP_REGS 128 | |||
#define R500_PFS_NUM_CONST_REGS 256 | |||
struct r300_pfs_compile_state; | |||
struct r500_pfs_compile_state; | |||
/** | |||
* Stores state that influences the compilation of a fragment program. | |||
*/ | |||
struct r300_fragment_program_external_state { | |||
struct { | |||
/** | |||
* If the sampler is used as a shadow sampler, | |||
* this field is: | |||
* 0 - GL_LUMINANCE | |||
* 1 - GL_INTENSITY | |||
* 2 - GL_ALPHA | |||
* depending on the depth texture mode. | |||
*/ | |||
GLuint depth_texture_mode : 2; | |||
/** | |||
* If the sampler is used as a shadow sampler, | |||
* this field is (texture_compare_func - GL_NEVER). | |||
* [e.g. if compare function is GL_LEQUAL, this field is 3] | |||
* | |||
* Otherwise, this field is 0. | |||
*/ | |||
GLuint texture_compare_func : 3; | |||
} unit[16]; | |||
}; | |||
struct r300_fragment_program_node { | |||
int tex_offset; /**< first tex instruction */ | |||
int tex_end; /**< last tex instruction, relative to tex_offset */ | |||
int alu_offset; /**< first ALU instruction */ | |||
int alu_end; /**< last ALU instruction, relative to alu_offset */ | |||
int flags; | |||
}; | |||
/** | |||
* Stores an R300 fragment program in its compiled-to-hardware form. | |||
*/ | |||
struct r300_fragment_program_code { | |||
struct { | |||
int length; /**< total # of texture instructions used */ | |||
GLuint inst[R300_PFS_MAX_TEX_INST]; | |||
} tex; | |||
struct { | |||
int length; /**< total # of ALU instructions used */ | |||
struct { | |||
GLuint inst0; | |||
GLuint inst1; | |||
GLuint inst2; | |||
GLuint inst3; | |||
} inst[R300_PFS_MAX_ALU_INST]; | |||
} alu; | |||
struct r300_fragment_program_node node[4]; | |||
int cur_node; | |||
int first_node_has_tex; | |||
/** | |||
* Remember which program register a given hardware constant | |||
* belongs to. | |||
*/ | |||
struct prog_src_register constant[R300_PFS_NUM_CONST_REGS]; | |||
int const_nr; | |||
int max_temp_idx; | |||
}; | |||
struct r500_fragment_program_code { | |||
struct { | |||
GLuint inst0; | |||
GLuint inst1; | |||
GLuint inst2; | |||
GLuint inst3; | |||
GLuint inst4; | |||
GLuint inst5; | |||
} inst[R500_PFS_MAX_INST]; | |||
int inst_offset; | |||
int inst_end; | |||
/** | |||
* Remember which program register a given hardware constant | |||
* belongs to. | |||
*/ | |||
struct prog_src_register constant[R500_PFS_NUM_CONST_REGS]; | |||
int const_nr; | |||
int max_temp_idx; | |||
}; | |||
/** | |||
* Store everything about a fragment program that is needed | |||
@@ -555,22 +449,10 @@ struct r300_fragment_program { | |||
GLboolean translated; | |||
GLboolean error; | |||
struct r300_fragment_program_external_state state; | |||
union rX00_fragment_program_code { | |||
struct r300_fragment_program_code r300; | |||
struct r500_fragment_program_code r500; | |||
} code; | |||
GLboolean writes_depth; | |||
GLuint optimization; | |||
struct r300_fragment_program *next; | |||
struct r300_fragment_program_external_state state; | |||
/* attribute that we are sending the WPOS in */ | |||
gl_frag_attrib wpos_attr; | |||
/* attribute that we are sending the fog coordinate in */ | |||
gl_frag_attrib fog_attr; | |||
struct rX00_fragment_program_code code; | |||
}; | |||
struct r300_fragment_program_cont { | |||
@@ -583,12 +465,6 @@ struct r300_fragment_program_cont { | |||
struct r300_fragment_program *progs; | |||
}; | |||
struct r300_fragment_program_compiler { | |||
r300ContextPtr r300; | |||
struct r300_fragment_program *fp; | |||
union rX00_fragment_program_code *code; | |||
struct gl_program *program; | |||
}; | |||
#define R300_MAX_AOS_ARRAYS 16 | |||
@@ -610,8 +486,6 @@ struct r300_swtcl_info { | |||
struct r300_vtable { | |||
void (* SetupRSUnit)(GLcontext *ctx); | |||
void (* SetupFragmentShaderTextures)(GLcontext *ctx, int *tmu_mappings); | |||
GLboolean (* BuildFragmentProgramHwCode)(struct r300_fragment_program_compiler *compiler); | |||
void (* FragmentProgramDump)(union rX00_fragment_program_code *code); | |||
void (* SetupPixelShader)(GLcontext *ctx); | |||
}; | |||
@@ -669,7 +543,7 @@ struct r300_context { | |||
uint32_t s3tc_force_disabled:1; | |||
uint32_t stencil_two_side_disabled:1; | |||
} options; | |||
struct r300_swtcl_info swtcl; | |||
struct r300_vertex_buffer vbuf; | |||
struct r300_index_buffer ind_buf; |
@@ -1,111 +0,0 @@ | |||
/* | |||
* Copyright (C) 2005 Ben Skeggs. | |||
* | |||
* All Rights Reserved. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sublicense, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the | |||
* next paragraph) shall be included in all copies or substantial | |||
* portions of the Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | |||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
*/ | |||
/* | |||
* Authors: | |||
* Ben Skeggs <darktama@iinet.net.au> | |||
* Jerome Glisse <j.glisse@gmail.com> | |||
*/ | |||
#ifndef __R300_FRAGPROG_H_ | |||
#define __R300_FRAGPROG_H_ | |||
#include "shader/program.h" | |||
#include "shader/prog_instruction.h" | |||
#include "r300_context.h" | |||
#include "radeon_program.h" | |||
#define DRI_CONF_FP_OPTIMIZATION_SPEED 0 | |||
#define DRI_CONF_FP_OPTIMIZATION_QUALITY 1 | |||
#if 1 | |||
/** | |||
* Fragment program helper macros | |||
*/ | |||
/* Produce unshifted source selectors */ | |||
#define FP_TMP(idx) (idx) | |||
#define FP_CONST(idx) ((idx) | (1 << 5)) | |||
/* Produce source/dest selector dword */ | |||
#define FP_SELC_MASK_NO 0 | |||
#define FP_SELC_MASK_X 1 | |||
#define FP_SELC_MASK_Y 2 | |||
#define FP_SELC_MASK_XY 3 | |||
#define FP_SELC_MASK_Z 4 | |||
#define FP_SELC_MASK_XZ 5 | |||
#define FP_SELC_MASK_YZ 6 | |||
#define FP_SELC_MASK_XYZ 7 | |||
#define FP_SELC(destidx,regmask,outmask,src0,src1,src2) \ | |||
(((destidx) << R300_ALU_DSTC_SHIFT) | \ | |||
(FP_SELC_MASK_##regmask << 23) | \ | |||
(FP_SELC_MASK_##outmask << 26) | \ | |||
((src0) << R300_ALU_SRC0C_SHIFT) | \ | |||
((src1) << R300_ALU_SRC1C_SHIFT) | \ | |||
((src2) << R300_ALU_SRC2C_SHIFT)) | |||
#define FP_SELA_MASK_NO 0 | |||
#define FP_SELA_MASK_W 1 | |||
#define FP_SELA(destidx,regmask,outmask,src0,src1,src2) \ | |||
(((destidx) << R300_ALU_DSTA_SHIFT) | \ | |||
(FP_SELA_MASK_##regmask << 23) | \ | |||
(FP_SELA_MASK_##outmask << 24) | \ | |||
((src0) << R300_ALU_SRC0A_SHIFT) | \ | |||
((src1) << R300_ALU_SRC1A_SHIFT) | \ | |||
((src2) << R300_ALU_SRC2A_SHIFT)) | |||
/* Produce unshifted argument selectors */ | |||
#define FP_ARGC(source) R300_ALU_ARGC_##source | |||
#define FP_ARGA(source) R300_ALU_ARGA_##source | |||
#define FP_ABS(arg) ((arg) | (1 << 6)) | |||
#define FP_NEG(arg) ((arg) ^ (1 << 5)) | |||
/* Produce instruction dword */ | |||
#define FP_INSTRC(opcode,arg0,arg1,arg2) \ | |||
(R300_ALU_OUTC_##opcode | \ | |||
((arg0) << R300_ALU_ARG0C_SHIFT) | \ | |||
((arg1) << R300_ALU_ARG1C_SHIFT) | \ | |||
((arg2) << R300_ALU_ARG2C_SHIFT)) | |||
#define FP_INSTRA(opcode,arg0,arg1,arg2) \ | |||
(R300_ALU_OUTA_##opcode | \ | |||
((arg0) << R300_ALU_ARG0A_SHIFT) | \ | |||
((arg1) << R300_ALU_ARG1A_SHIFT) | \ | |||
((arg2) << R300_ALU_ARG2A_SHIFT)) | |||
#endif | |||
extern GLboolean r300BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler); | |||
extern void r300FragmentProgramDump(union rX00_fragment_program_code *c); | |||
extern GLboolean r300_transform_TEX(struct radeon_transform_context *t, struct prog_instruction* orig_inst, void* data); | |||
#endif |
@@ -43,175 +43,13 @@ | |||
#include "shader/prog_print.h" | |||
#include "r300_state.h" | |||
#include "r300_fragprog.h" | |||
#include "r300_fragprog_swizzle.h" | |||
#include "r500_fragprog.h" | |||
#include "radeon_program.h" | |||
#include "radeon_program_alu.h" | |||
#include "compiler/radeon_program.h" | |||
#include "compiler/radeon_program_alu.h" | |||
#include "compiler/r300_fragprog_swizzle.h" | |||
#include "compiler/r300_fragprog.h" | |||
#include "compiler/r500_fragprog.h" | |||
static void nqssadce_init(struct nqssadce_state* s) | |||
{ | |||
s->Outputs[FRAG_RESULT_COLOR].Sourced = WRITEMASK_XYZW; | |||
s->Outputs[FRAG_RESULT_DEPTH].Sourced = WRITEMASK_W; | |||
} | |||
/** | |||
* Transform the program to support fragment.position. | |||
* | |||
* Introduce a small fragment at the start of the program that will be | |||
* the only code that directly reads the FRAG_ATTRIB_WPOS input. | |||
* All other code pieces that reference that input will be rewritten | |||
* to read from a newly allocated temporary. | |||
* | |||
*/ | |||
static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
GLuint InputsRead = compiler->fp->Base->InputsRead; | |||
if (!(InputsRead & FRAG_BIT_WPOS)) { | |||
compiler->fp->wpos_attr = FRAG_ATTRIB_MAX; | |||
return; | |||
} | |||
static gl_state_index tokens[STATE_LENGTH] = { | |||
STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0 | |||
}; | |||
struct prog_instruction *fpi; | |||
GLuint window_index; | |||
int i = 0; | |||
for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i) | |||
{ | |||
if (!(InputsRead & (1 << i))) { | |||
InputsRead &= ~(1 << FRAG_ATTRIB_WPOS); | |||
InputsRead |= 1 << i; | |||
compiler->fp->Base->InputsRead = InputsRead; | |||
compiler->fp->wpos_attr = i; | |||
break; | |||
} | |||
} | |||
GLuint tempregi = _mesa_find_free_register(compiler->program, PROGRAM_TEMPORARY); | |||
_mesa_insert_instructions(compiler->program, 0, 3); | |||
fpi = compiler->program->Instructions; | |||
i = 0; | |||
/* perspective divide */ | |||
fpi[i].Opcode = OPCODE_RCP; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_W; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_INPUT; | |||
fpi[i].SrcReg[0].Index = compiler->fp->wpos_attr; | |||
fpi[i].SrcReg[0].Swizzle = SWIZZLE_WWWW; | |||
i++; | |||
fpi[i].Opcode = OPCODE_MUL; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_XYZ; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_INPUT; | |||
fpi[i].SrcReg[0].Index = compiler->fp->wpos_attr; | |||
fpi[i].SrcReg[0].Swizzle = SWIZZLE_XYZW; | |||
fpi[i].SrcReg[1].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[1].Index = tempregi; | |||
fpi[i].SrcReg[1].Swizzle = SWIZZLE_WWWW; | |||
i++; | |||
/* viewport transformation */ | |||
window_index = _mesa_add_state_reference(compiler->program->Parameters, tokens); | |||
fpi[i].Opcode = OPCODE_MAD; | |||
fpi[i].DstReg.File = PROGRAM_TEMPORARY; | |||
fpi[i].DstReg.Index = tempregi; | |||
fpi[i].DstReg.WriteMask = WRITEMASK_XYZ; | |||
fpi[i].DstReg.CondMask = COND_TR; | |||
fpi[i].SrcReg[0].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[0].Index = tempregi; | |||
fpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
fpi[i].SrcReg[1].File = PROGRAM_STATE_VAR; | |||
fpi[i].SrcReg[1].Index = window_index; | |||
fpi[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
fpi[i].SrcReg[2].File = PROGRAM_STATE_VAR; | |||
fpi[i].SrcReg[2].Index = window_index; | |||
fpi[i].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO); | |||
i++; | |||
for (; i < compiler->program->NumInstructions; ++i) { | |||
int reg; | |||
for (reg = 0; reg < 3; reg++) { | |||
if (fpi[i].SrcReg[reg].File == PROGRAM_INPUT && | |||
fpi[i].SrcReg[reg].Index == FRAG_ATTRIB_WPOS) { | |||
fpi[i].SrcReg[reg].File = PROGRAM_TEMPORARY; | |||
fpi[i].SrcReg[reg].Index = tempregi; | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Rewrite fragment.fogcoord to use a texture coordinate slot. | |||
* Note that fogcoord is forced into an X001 pattern, and this enforcement | |||
* is done here. | |||
* | |||
* See also the counterpart rewriting for vertex programs. | |||
*/ | |||
static void rewriteFog(struct r300_fragment_program_compiler *compiler) | |||
{ | |||
struct r300_fragment_program *fp = compiler->fp; | |||
GLuint InputsRead; | |||
int i; | |||
InputsRead = fp->Base->InputsRead; | |||
if (!(InputsRead & FRAG_BIT_FOGC)) { | |||
fp->fog_attr = FRAG_ATTRIB_MAX; | |||
return; | |||
} | |||
for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i) | |||
{ | |||
if (!(InputsRead & (1 << i))) { | |||
InputsRead &= ~(1 << FRAG_ATTRIB_FOGC); | |||
InputsRead |= 1 << i; | |||
fp->Base->InputsRead = InputsRead; | |||
fp->fog_attr = i; | |||
break; | |||
} | |||
} | |||
{ | |||
struct prog_instruction *inst; | |||
inst = compiler->program->Instructions; | |||
while (inst->Opcode != OPCODE_END) { | |||
const int src_regs = _mesa_num_inst_src_regs(inst->Opcode); | |||
for (i = 0; i < src_regs; ++i) { | |||
if (inst->SrcReg[i].File == PROGRAM_INPUT && inst->SrcReg[i].Index == FRAG_ATTRIB_FOGC) { | |||
inst->SrcReg[i].Index = fp->fog_attr; | |||
inst->SrcReg[i].Swizzle = combine_swizzles( | |||
MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), | |||
inst->SrcReg[i].Swizzle); | |||
} | |||
} | |||
++inst; | |||
} | |||
} | |||
} | |||
static GLuint build_dtm(GLuint depthmode) | |||
{ | |||
@@ -251,121 +89,23 @@ static void build_state( | |||
} | |||
} | |||
static void rewrite_depth_out(struct gl_program *prog) | |||
{ | |||
struct prog_instruction *inst; | |||
for (inst = prog->Instructions; inst->Opcode != OPCODE_END; ++inst) { | |||
if (inst->DstReg.File != PROGRAM_OUTPUT || inst->DstReg.Index != FRAG_RESULT_DEPTH) | |||
continue; | |||
if (inst->DstReg.WriteMask & WRITEMASK_Z) { | |||
inst->DstReg.WriteMask = WRITEMASK_W; | |||
} else { | |||
inst->DstReg.WriteMask = 0; | |||
continue; | |||
} | |||
switch (inst->Opcode) { | |||
case OPCODE_FRC: | |||
case OPCODE_MOV: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
break; | |||
case OPCODE_ADD: | |||
case OPCODE_MAX: | |||
case OPCODE_MIN: | |||
case OPCODE_MUL: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]); | |||
break; | |||
case OPCODE_CMP: | |||
case OPCODE_MAD: | |||
inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]); | |||
inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]); | |||
inst->SrcReg[2] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[2]); | |||
break; | |||
default: | |||
// Scalar instructions needn't be reswizzled | |||
break; | |||
} | |||
} | |||
} | |||
void r300TranslateFragmentShader(GLcontext *ctx, struct r300_fragment_program *fp) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
struct r300_fragment_program_compiler compiler; | |||
compiler.r300 = r300; | |||
compiler.fp = fp; | |||
compiler.ctx = ctx; | |||
compiler.code = &fp->code; | |||
compiler.state = fp->state; | |||
compiler.program = fp->Base; | |||
compiler.is_r500 = (r300->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) ? GL_TRUE : GL_FALSE; | |||
compiler.debug = (RADEON_DEBUG & DEBUG_PIXEL) ? GL_TRUE : GL_FALSE; | |||
if (RADEON_DEBUG & DEBUG_PIXEL) { | |||
fflush(stdout); | |||
_mesa_printf("Fragment Program: Initial program:\n"); | |||
_mesa_print_program(compiler.program); | |||
fflush(stdout); | |||
} | |||
insert_WPOS_trailer(&compiler); | |||
rewriteFog(&compiler); | |||
rewrite_depth_out(compiler.program); | |||
if (r300->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { | |||
struct radeon_program_transformation transformations[] = { | |||
{ &r500_transform_TEX, &compiler }, | |||
{ &radeonTransformALU, 0 }, | |||
{ &radeonTransformDeriv, 0 }, | |||
{ &radeonTransformTrigScale, 0 } | |||
}; | |||
radeonLocalTransform(ctx, compiler.program, 4, transformations); | |||
} else { | |||
struct radeon_program_transformation transformations[] = { | |||
{ &r300_transform_TEX, &compiler }, | |||
{ &radeonTransformALU, 0 }, | |||
{ &radeonTransformTrigSimple, 0 } | |||
}; | |||
radeonLocalTransform(ctx, compiler.program, 3, transformations); | |||
} | |||
if (RADEON_DEBUG & DEBUG_PIXEL) { | |||
_mesa_printf("Fragment Program: After native rewrite:\n"); | |||
_mesa_print_program(compiler.program); | |||
fflush(stdout); | |||
} | |||
if (r300->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { | |||
struct radeon_nqssadce_descr nqssadce = { | |||
.Init = &nqssadce_init, | |||
.IsNativeSwizzle = &r500FPIsNativeSwizzle, | |||
.BuildSwizzle = &r500FPBuildSwizzle | |||
}; | |||
radeonNqssaDce(ctx, compiler.program, &nqssadce); | |||
} else { | |||
struct radeon_nqssadce_descr nqssadce = { | |||
.Init = &nqssadce_init, | |||
.IsNativeSwizzle = &r300FPIsNativeSwizzle, | |||
.BuildSwizzle = &r300FPBuildSwizzle | |||
}; | |||
radeonNqssaDce(ctx, compiler.program, &nqssadce); | |||
} | |||
if (RADEON_DEBUG & DEBUG_PIXEL) { | |||
_mesa_printf("Compiler: after NqSSA-DCE:\n"); | |||
_mesa_print_program(compiler.program); | |||
fflush(stdout); | |||
} | |||
if (!r300->vtbl.BuildFragmentProgramHwCode(&compiler)) | |||
if (!r3xx_compile_fragment_program(&compiler)) | |||
fp->error = GL_TRUE; | |||
fp->translated = GL_TRUE; | |||
if (fp->error || (RADEON_DEBUG & DEBUG_PIXEL)) | |||
r300->vtbl.FragmentProgramDump(&fp->code); | |||
} | |||
struct r300_fragment_program *r300SelectFragmentShader(GLcontext *ctx) |
@@ -55,7 +55,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "r300_vertprog.h" | |||
#include "radeon_reg.h" | |||
#include "r300_emit.h" | |||
#include "r300_fragprog.h" | |||
#include "r300_context.h" | |||
#include "vblank.h" | |||
@@ -66,6 +65,66 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#define CLEARBUFFER_DEPTH 0x2 | |||
#define CLEARBUFFER_STENCIL 0x4 | |||
#if 1 | |||
/** | |||
* Fragment program helper macros | |||
*/ | |||
/* Produce unshifted source selectors */ | |||
#define FP_TMP(idx) (idx) | |||
#define FP_CONST(idx) ((idx) | (1 << 5)) | |||
/* Produce source/dest selector dword */ | |||
#define FP_SELC_MASK_NO 0 | |||
#define FP_SELC_MASK_X 1 | |||
#define FP_SELC_MASK_Y 2 | |||
#define FP_SELC_MASK_XY 3 | |||
#define FP_SELC_MASK_Z 4 | |||
#define FP_SELC_MASK_XZ 5 | |||
#define FP_SELC_MASK_YZ 6 | |||
#define FP_SELC_MASK_XYZ 7 | |||
#define FP_SELC(destidx,regmask,outmask,src0,src1,src2) \ | |||
(((destidx) << R300_ALU_DSTC_SHIFT) | \ | |||
(FP_SELC_MASK_##regmask << 23) | \ | |||
(FP_SELC_MASK_##outmask << 26) | \ | |||
((src0) << R300_ALU_SRC0C_SHIFT) | \ | |||
((src1) << R300_ALU_SRC1C_SHIFT) | \ | |||
((src2) << R300_ALU_SRC2C_SHIFT)) | |||
#define FP_SELA_MASK_NO 0 | |||
#define FP_SELA_MASK_W 1 | |||
#define FP_SELA(destidx,regmask,outmask,src0,src1,src2) \ | |||
(((destidx) << R300_ALU_DSTA_SHIFT) | \ | |||
(FP_SELA_MASK_##regmask << 23) | \ | |||
(FP_SELA_MASK_##outmask << 24) | \ | |||
((src0) << R300_ALU_SRC0A_SHIFT) | \ | |||
((src1) << R300_ALU_SRC1A_SHIFT) | \ | |||
((src2) << R300_ALU_SRC2A_SHIFT)) | |||
/* Produce unshifted argument selectors */ | |||
#define FP_ARGC(source) R300_ALU_ARGC_##source | |||
#define FP_ARGA(source) R300_ALU_ARGA_##source | |||
#define FP_ABS(arg) ((arg) | (1 << 6)) | |||
#define FP_NEG(arg) ((arg) ^ (1 << 5)) | |||
/* Produce instruction dword */ | |||
#define FP_INSTRC(opcode,arg0,arg1,arg2) \ | |||
(R300_ALU_OUTC_##opcode | \ | |||
((arg0) << R300_ALU_ARG0C_SHIFT) | \ | |||
((arg1) << R300_ALU_ARG1C_SHIFT) | \ | |||
((arg2) << R300_ALU_ARG2C_SHIFT)) | |||
#define FP_INSTRA(opcode,arg0,arg1,arg2) \ | |||
(R300_ALU_OUTA_##opcode | \ | |||
((arg0) << R300_ALU_ARG0A_SHIFT) | \ | |||
((arg1) << R300_ALU_ARG1A_SHIFT) | \ | |||
((arg2) << R300_ALU_ARG2A_SHIFT)) | |||
#endif | |||
static void r300EmitClearState(GLcontext * ctx); | |||
static void r300ClearBuffer(r300ContextPtr r300, int flags, | |||
@@ -546,7 +605,7 @@ static int r300KernelClear(GLcontext *ctx, GLuint flags) | |||
/* Make sure it fits there. */ | |||
radeon_cs_space_reset_bos(r300->radeon.cmdbuf.cs); | |||
if (flags & BUFFER_BIT_COLOR0) { | |||
rrb = radeon_get_renderbuffer(&rfb->base, BUFFER_COLOR0); | |||
radeon_cs_space_add_persistent_bo(r300->radeon.cmdbuf.cs, |
@@ -62,8 +62,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "r300_emit.h" | |||
#include "r300_tex.h" | |||
#include "r300_fragprog_common.h" | |||
#include "r300_fragprog.h" | |||
#include "r500_fragprog.h" | |||
#include "r300_render.h" | |||
#include "r300_vertprog.h" | |||
@@ -458,7 +456,7 @@ static GLboolean current_fragment_program_writes_depth(GLcontext* ctx) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
return ctx->FragmentProgram._Current && r300->selected_fp->writes_depth; | |||
return ctx->FragmentProgram._Current && r300->selected_fp->code.writes_depth; | |||
} | |||
static void r300SetEarlyZState(GLcontext * ctx) | |||
@@ -1230,7 +1228,7 @@ static void r300SetupFragmentShaderTextures(GLcontext *ctx, int *tmu_mappings) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
int i; | |||
struct r300_fragment_program_code *code = &r300->selected_fp->code.r300; | |||
struct r300_fragment_program_code *code = &r300->selected_fp->code.code.r300; | |||
R300_STATECHANGE(r300, fpt); | |||
@@ -1272,7 +1270,7 @@ static void r500SetupFragmentShaderTextures(GLcontext *ctx, int *tmu_mappings) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
int i; | |||
struct r500_fragment_program_code *code = &r300->selected_fp->code.r500; | |||
struct r500_fragment_program_code *code = &r300->selected_fp->code.code.r500; | |||
/* find all the texture instructions and relocate the texture units */ | |||
for (i = 0; i < code->inst_end + 1; i++) { | |||
@@ -2063,7 +2061,7 @@ static void r300SetupPixelShader(GLcontext *ctx) | |||
struct r300_fragment_program_code *code; | |||
int i, k; | |||
code = &fp->code.r300; | |||
code = &fp->code.code.r300; | |||
R300_STATECHANGE(rmesa, fpi[0]); | |||
R300_STATECHANGE(rmesa, fpi[1]); | |||
@@ -2137,7 +2135,7 @@ static void r500SetupPixelShader(GLcontext *ctx) | |||
((drm_r300_cmd_header_t *) rmesa->hw.r500fp.cmd)->r500fp.count = 0; | |||
((drm_r300_cmd_header_t *) rmesa->hw.r500fp_const.cmd)->r500fp.count = 0; | |||
code = &fp->code.r500; | |||
code = &fp->code.code.r500; | |||
R300_STATECHANGE(rmesa, fp); | |||
rmesa->hw.fp.cmd[R500_FP_PIXSIZE] = code->max_temp_idx; | |||
@@ -2345,13 +2343,9 @@ void r300InitShaderFunctions(r300ContextPtr r300) | |||
r300->vtbl.SetupRSUnit = r500SetupRSUnit; | |||
r300->vtbl.SetupPixelShader = r500SetupPixelShader; | |||
r300->vtbl.SetupFragmentShaderTextures = r500SetupFragmentShaderTextures; | |||
r300->vtbl.BuildFragmentProgramHwCode = r500BuildFragmentProgramHwCode; | |||
r300->vtbl.FragmentProgramDump = r500FragmentProgramDump; | |||
} else { | |||
r300->vtbl.SetupRSUnit = r300SetupRSUnit; | |||
r300->vtbl.SetupPixelShader = r300SetupPixelShader; | |||
r300->vtbl.SetupFragmentShaderTextures = r300SetupFragmentShaderTextures; | |||
r300->vtbl.BuildFragmentProgramHwCode = r300BuildFragmentProgramHwCode; | |||
r300->vtbl.FragmentProgramDump = r300FragmentProgramDump; | |||
} | |||
} |
@@ -150,16 +150,16 @@ void r300ChooseSwtclVertexFormat(GLcontext *ctx, GLuint *_InputsRead, GLuint *_ | |||
ADD_ATTR(VERT_ATTRIB_POINT_SIZE, R300_DATA_TYPE_FLOAT_1, SWTCL_OVM_POINT_SIZE, swiz, MASK_X, 0); | |||
} | |||
if (rmesa->selected_fp->wpos_attr != FRAG_ATTRIB_MAX) { | |||
int tex_id = rmesa->selected_fp->wpos_attr - FRAG_ATTRIB_TEX0; | |||
if (rmesa->selected_fp->code.wpos_attr != FRAG_ATTRIB_MAX) { | |||
int tex_id = rmesa->selected_fp->code.wpos_attr - FRAG_ATTRIB_TEX0; | |||
VB->AttribPtr[VERT_ATTRIB_TEX0 + tex_id] = VB->AttribPtr[VERT_ATTRIB_POS]; | |||
VB->TexCoordPtr[tex_id] = VB->AttribPtr[VERT_ATTRIB_POS]; | |||
RENDERINPUTS_SET(tnl->render_inputs_bitset, _TNL_ATTRIB_TEX0 + tex_id); | |||
} | |||
if (rmesa->selected_fp->fog_attr != FRAG_ATTRIB_MAX) { | |||
int tex_id = rmesa->selected_fp->fog_attr - FRAG_ATTRIB_TEX0; | |||
if (rmesa->selected_fp->code.fog_attr != FRAG_ATTRIB_MAX) { | |||
int tex_id = rmesa->selected_fp->code.fog_attr - FRAG_ATTRIB_TEX0; | |||
VB->AttribPtr[VERT_ATTRIB_TEX0 + tex_id] = VB->AttribPtr[VERT_ATTRIB_FOG]; | |||
VB->TexCoordPtr[tex_id] = VB->AttribPtr[VERT_ATTRIB_FOG]; |
@@ -40,7 +40,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "shader/prog_statevars.h" | |||
#include "tnl/tnl.h" | |||
#include "radeon_nqssadce.h" | |||
#include "compiler/radeon_nqssadce.h" | |||
#include "r300_context.h" | |||
#include "r300_state.h" | |||
@@ -1558,12 +1558,12 @@ static struct r300_vertex_program *build_program(GLcontext *ctx, | |||
_mesa_insert_mvp_code(ctx, vp->Base); | |||
} | |||
if (r300->selected_fp->wpos_attr != FRAG_ATTRIB_MAX) { | |||
pos_as_texcoord(&vp->Base->Base, r300->selected_fp->wpos_attr - FRAG_ATTRIB_TEX0); | |||
if (r300->selected_fp->code.wpos_attr != FRAG_ATTRIB_MAX) { | |||
pos_as_texcoord(&vp->Base->Base, r300->selected_fp->code.wpos_attr - FRAG_ATTRIB_TEX0); | |||
} | |||
if (r300->selected_fp->fog_attr != FRAG_ATTRIB_MAX) { | |||
fog_as_texcoord(&vp->Base->Base, r300->selected_fp->fog_attr - FRAG_ATTRIB_TEX0); | |||
if (r300->selected_fp->code.fog_attr != FRAG_ATTRIB_MAX) { | |||
fog_as_texcoord(&vp->Base->Base, r300->selected_fp->code.fog_attr - FRAG_ATTRIB_TEX0); | |||
} | |||
addArtificialOutputs(ctx, prog); | |||
@@ -1640,8 +1640,8 @@ struct r300_vertex_program * r300SelectVertexShader(GLcontext *ctx) | |||
vpc = (struct r300_vertex_program_cont *)ctx->VertexProgram._Current; | |||
wanted_key.FpReads = r300->selected_fp->Base->InputsRead; | |||
wanted_key.FogAttr = r300->selected_fp->fog_attr; | |||
wanted_key.WPosAttr = r300->selected_fp->wpos_attr; | |||
wanted_key.FogAttr = r300->selected_fp->code.fog_attr; | |||
wanted_key.WPosAttr = r300->selected_fp->code.wpos_attr; | |||
for (vp = vpc->progs; vp; vp = vp->next) { | |||
if (_mesa_memcmp(&vp->key, &wanted_key, sizeof(wanted_key)) |
@@ -57,7 +57,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "r200_tex.h" | |||
#elif RADEON_COMMON && defined(RADEON_COMMON_FOR_R300) | |||
#include "r300_context.h" | |||
#include "r300_fragprog.h" | |||
#include "r300_tex.h" | |||
#elif RADEON_COMMON && defined(RADEON_COMMON_FOR_R600) | |||
#include "r600_context.h" | |||
@@ -150,6 +149,9 @@ extern const struct dri_extension point_extensions[]; | |||
#elif RADEON_COMMON && (defined(RADEON_COMMON_FOR_R300) || defined(RADEON_COMMON_FOR_R600)) | |||
#define DRI_CONF_FP_OPTIMIZATION_SPEED 0 | |||
#define DRI_CONF_FP_OPTIMIZATION_QUALITY 1 | |||
/* TODO: integrate these into xmlpool.h! */ | |||
#define DRI_CONF_MAX_TEXTURE_IMAGE_UNITS(def,min,max) \ | |||
DRI_CONF_OPT_BEGIN_V(texture_image_units,int,def, # min ":" # max ) \ |