#include "glheader.h" #include "state.h" #include "imports.h" #include "enums.h" #include "macros.h" #include "context.h" #include "dd.h" #include "simple_list.h" #include "api_arrayelt.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" #include "array_cache/acache.h" #include "tnl/tnl.h" #include "texformat.h" #include "radeon_ioctl.h" #include "radeon_state.h" #include "r300_context.h" #if USE_ARB_F_P == 0 #include "r300_ioctl.h" #include "r300_state.h" #include "r300_reg.h" #include "r300_program.h" #include "r300_emit.h" #include "r300_fixed_pipelines.h" #include "r300_tex.h" #include "pixel_shader.h" #include "r300_texprog.h" /* TODO: we probably should have a better way to emit alu instructions */ #define INST0 p->alu.inst[p->alu.length].inst0 = #define INST1 p->alu.inst[p->alu.length].inst1 = #define INST2 p->alu.inst[p->alu.length].inst2 = #define INST3 p->alu.inst[p->alu.length].inst3 = #define EMIT_INST p->alu.length++ void emit_tex(struct r300_pixel_shader_program *p, GLuint dest, GLuint unit, GLuint src) { p->tex.inst[p->tex.length++] = 0 | (src << R300_FPITX_SRC_SHIFT) | (dest << R300_FPITX_DST_SHIFT) | (unit << R300_FPITX_IMAGE_SHIFT) /* I don't know if this is needed, but the hardcoded 0x18000 set it, so I will too */ | (3 << 15); // fprintf(stderr, "emit texinst: 0x%x\n", p->tex.inst[p->tex.length-1]); } GLuint get_source(struct r300_pixel_shader_state *ps, GLenum src, GLuint unit, GLuint tc_reg) { switch (src) { case GL_TEXTURE: if (!ps->have_sample) { emit_tex(&ps->program, tc_reg, unit, tc_reg); ps->have_sample = 1; } return tc_reg; case GL_CONSTANT: WARN_ONCE("TODO: Implement envcolor\n"); return ps->color_reg; case GL_PRIMARY_COLOR: return ps->color_reg; case GL_PREVIOUS: return ps->src_previous; default: WARN_ONCE("Unknown source enum\n"); return ps->src_previous; } } GLuint get_temp(struct r300_pixel_shader_program *p) { return p->temp_register_count++; } inline void emit_texenv_color(r300ContextPtr r300, struct r300_pixel_shader_state *ps, GLuint out, GLenum envmode, GLenum format, GLuint unit, GLuint tc_reg) { struct r300_pixel_shader_program *p = &ps->program; const GLuint Cp = get_source(ps, GL_PREVIOUS, unit, tc_reg); const GLuint Cs = get_source(ps, GL_TEXTURE, unit, tc_reg); switch(envmode) { case GL_DECAL: /* TODO */ case GL_BLEND: /* TODO */ case GL_REPLACE: INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO); switch (format) { case GL_ALPHA: // Cv = Cp INST1 EASY_PFS_INSTR1(out, Cp, PFS_FLAG_CONST, PFS_FLAG_CONST, ALL, NONE); break; default: // Cv = Cs INST1 EASY_PFS_INSTR1(out, Cs, PFS_FLAG_CONST, PFS_FLAG_CONST, ALL, NONE); break; } break; case GL_MODULATE: switch (format) { case GL_ALPHA: // Cv = Cp INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO); INST1 EASY_PFS_INSTR1(out, Cp, PFS_FLAG_CONST, PFS_FLAG_CONST, ALL, NONE); break; default: // Cv = CpCs INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, SRC1C_XYZ, ZERO); INST1 EASY_PFS_INSTR1(out, Cp, Cs, PFS_FLAG_CONST, ALL, NONE); break; } break; case GL_ADD: switch (format) { case GL_ALPHA: // Cv = Cp INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO); INST1 EASY_PFS_INSTR1(out, Cp, PFS_FLAG_CONST, PFS_FLAG_CONST, ALL, NONE); break; default: // Cv = Cp + Cs INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, SRC1C_XYZ); INST1 EASY_PFS_INSTR1(out, Cp, Cs, PFS_FLAG_CONST, ALL, NONE); break; } break; default: fprintf(stderr, "%s: should never get here!\n", __func__); break; } return; } inline void emit_texenv_alpha(r300ContextPtr r300, struct r300_pixel_shader_state *ps, GLuint out, GLenum envmode, GLenum format, GLuint unit, GLuint tc_reg) { struct r300_pixel_shader_program *p = &ps->program; const GLuint Ap = get_source(ps, GL_PREVIOUS, unit, tc_reg); const GLuint As = get_source(ps, GL_TEXTURE, unit, tc_reg); switch(envmode) { case GL_DECAL: /* TODO */ case GL_BLEND: /* TODO */ case GL_REPLACE: INST2 EASY_PFS_INSTR2(MAD, SRC0A, ONE, ZERO); switch (format) { case GL_LUMINANCE: case GL_RGB: // Av = Ap INST3 EASY_PFS_INSTR3(out, Ap, PFS_FLAG_CONST, PFS_FLAG_CONST, REG); break; default: INST3 EASY_PFS_INSTR3(out, As, PFS_FLAG_CONST, PFS_FLAG_CONST, REG); break; } break; case GL_MODULATE: case GL_ADD: switch (format) { case GL_LUMINANCE: case GL_RGB: // Av = Ap INST2 EASY_PFS_INSTR2(MAD, SRC0A, ONE, ZERO); INST3 EASY_PFS_INSTR3(out, Ap, PFS_FLAG_CONST, PFS_FLAG_CONST, REG); break; default: // Av = ApAs INST2 EASY_PFS_INSTR2(MAD, SRC0A, SRC1A, ZERO); INST3 EASY_PFS_INSTR3(out, Ap, As, PFS_FLAG_CONST, REG); break; } break; default: fprintf(stderr, "%s: should never get here!\n", __func__); break; } return; } GLuint emit_texenv(r300ContextPtr r300, GLuint tc_reg, GLuint unit) { struct r300_pixel_shader_state *ps = &r300->state.pixel_shader; struct r300_pixel_shader_program *p = &ps->program; GLcontext *ctx = r300->radeon.glCtx; struct gl_texture_object *texobj = ctx->Texture.Unit[unit]._Current; GLenum envmode = ctx->Texture.Unit[unit].EnvMode; GLenum format = texobj->Image[0][texobj->BaseLevel]->Format; const GLuint out = tc_reg; const GLuint Cf = get_source(ps, GL_PRIMARY_COLOR, unit, tc_reg); WARN_ONCE("Texture environments are currently incomplete / wrong! Help me!\n"); // fprintf(stderr, "EnvMode = %s\n", _mesa_lookup_enum_by_nr(ctx->Texture.Unit[unit].EnvMode)); switch (envmode) { case GL_REPLACE: case GL_MODULATE: case GL_DECAL: case GL_BLEND: case GL_ADD: /* Maybe these should be combined? I thought it'd be messy */ emit_texenv_color(r300, ps, out, envmode, format, unit, tc_reg); emit_texenv_alpha(r300, ps, out, envmode, format, unit, tc_reg); EMIT_INST; return out; break; case GL_COMBINE: WARN_ONCE("EnvMode == GL_COMBINE unsupported! Help Me!!\n"); return get_source(ps, GL_TEXTURE, unit, tc_reg); break; default: WARN_ONCE("Unknown EnvMode == %d, name=%s\n", envmode, _mesa_lookup_enum_by_nr(envmode)); return get_source(ps, GL_TEXTURE, unit, tc_reg); break; } } void r300GenerateTextureFragmentShader(r300ContextPtr r300) { struct r300_pixel_shader_state *ps = &r300->state.pixel_shader; struct r300_pixel_shader_program *p = &ps->program; GLcontext *ctx = r300->radeon.glCtx; int i, tc_reg; GLuint OutputsWritten; if(hw_tcl_on) OutputsWritten = CURRENT_VERTEX_SHADER(ctx)->OutputsWritten; p->tex.length = 0; p->alu.length = 0; p->active_nodes = 1; p->first_node_has_tex = 1; p->temp_register_count = r300->state.texture.tc_count + 1; /* texcoords and colour reg */ ps->color_reg = r300->state.texture.tc_count; ps->src_previous = ps->color_reg; tc_reg = 0; for (i=0;iConst.MaxTextureUnits;i++) { if (TMU_ENABLED(ctx, i)) { ps->have_sample = 0; ps->src_previous = emit_texenv(r300, tc_reg, i); tc_reg++; } } /* Do a MOV from last output, to destination reg.. This won't be needed when we * have a better way of emitting alu instructions */ INST0 EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO); INST1 EASY_PFS_INSTR1(0, ps->src_previous, PFS_FLAG_CONST, PFS_FLAG_CONST, NONE, ALL); INST2 EASY_PFS_INSTR2(MAD, SRC0A, ONE, ZERO); INST3 EASY_PFS_INSTR3(0, ps->src_previous, PFS_FLAG_CONST, PFS_FLAG_CONST, OUTPUT); EMIT_INST; p->node[3].tex_end = ps->program.tex.length - 1; p->node[3].tex_offset = 0; p->node[3].alu_end = ps->program.alu.length - 1; p->node[3].alu_offset = 0; p->tex_end = ps->program.tex.length - 1; p->tex_offset = 0; p->alu_end = ps->program.alu.length - 1; p->alu_offset = 0; } #endif // USE_ARB_F_P == 0