From 45fc069600ddbfe07a0a0cd5280161a8c7c55dd0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?St=C3=A9phane=20Marchesin?= Date: Mon, 25 Jun 2012 19:45:56 -0700 Subject: [PATCH] i915g: Implement sRGB textures Since we don't have them in hw we emulate them in the shader. Although not recommended by the spec it is legit. As a side effect we also get GL 2.1. I think this is as far as we can take the i915. --- src/gallium/drivers/i915/i915_context.h | 2 + src/gallium/drivers/i915/i915_screen.c | 5 +- src/gallium/drivers/i915/i915_state_emit.c | 128 ++++++++++++++++-- src/gallium/drivers/i915/i915_state_sampler.c | 3 + src/gallium/drivers/i915/i915_state_static.c | 2 +- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/i915/i915_context.h b/src/gallium/drivers/i915/i915_context.h index b019c9f342a..16b0c57166d 100644 --- a/src/gallium/drivers/i915/i915_context.h +++ b/src/gallium/drivers/i915/i915_context.h @@ -155,6 +155,8 @@ struct i915_state unsigned sampler[I915_TEX_UNITS][3]; unsigned sampler_enable_flags; unsigned sampler_enable_nr; + boolean sampler_srgb[I915_TEX_UNITS]; + int srgb_const_offset; /* texture image buffers */ unsigned texbuffer[I915_TEX_UNITS][2]; diff --git a/src/gallium/drivers/i915/i915_screen.c b/src/gallium/drivers/i915/i915_screen.c index 9f293392f81..ff352035fb0 100644 --- a/src/gallium/drivers/i915/i915_screen.c +++ b/src/gallium/drivers/i915/i915_screen.c @@ -110,7 +110,9 @@ i915_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe_sha return PIPE_MAX_VERTEX_SAMPLERS; else return 0; - default: + case PIPE_SHADER_CAP_INTEGERS: + return 1; + default: return draw_get_shader_param(shader, cap); } case PIPE_SHADER_FRAGMENT: @@ -290,6 +292,7 @@ i915_is_format_supported(struct pipe_screen *screen, { static const enum pipe_format tex_supported[] = { PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_FORMAT_B8G8R8A8_SRGB, PIPE_FORMAT_B8G8R8X8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM, PIPE_FORMAT_R8G8B8X8_UNORM, diff --git a/src/gallium/drivers/i915/i915_state_emit.c b/src/gallium/drivers/i915/i915_state_emit.c index 8ab8fb8cd74..ac999792c06 100644 --- a/src/gallium/drivers/i915/i915_state_emit.c +++ b/src/gallium/drivers/i915/i915_state_emit.c @@ -30,6 +30,7 @@ #include "i915_context.h" #include "i915_batch.h" #include "i915_debug.h" +#include "i915_fpc.h" #include "i915_resource.h" #include "pipe/p_context.h" @@ -313,11 +314,42 @@ emit_sampler(struct i915_context *i915) } } +static boolean is_tex_instruction(uint32_t* instruction) +{ + uint32_t op = instruction[0] &0xFF000000; + return ( (op == T0_TEXLD) || + (op == T0_TEXLDP) || + (op == T0_TEXLDB)); +} + +static uint32_t tex_sampler(uint32_t* instruction) +{ + return ( instruction[0] & T0_SAMPLER_NR_MASK); +} + +static uint additional_constants(struct i915_context *i915) +{ + int i; + + for (i = 0 ; i < i915->fs->program_len; i+=3) { + if ( is_tex_instruction(i915->fs->program + i)) { + int sampler = tex_sampler(i915->fs->program + i); + assert(sampler < I915_TEX_UNITS); + if ( i915->current.sampler_srgb[sampler] ) + return 1; + } + } + return 0; +} + static void validate_constants(struct i915_context *i915, unsigned *batch_space) { - *batch_space = i915->fs->num_constants ? + int nr = i915->fs->num_constants ? 2 + 4*i915->fs->num_constants : 0; + + nr += 4*additional_constants(i915); + *batch_space = nr; } static void @@ -326,8 +358,11 @@ emit_constants(struct i915_context *i915) /* Collate the user-defined constants with the fragment shader's * immediates according to the constant_flags[] array. */ - const uint nr = i915->fs->num_constants; + const uint nr = i915->fs->num_constants + additional_constants(i915); + + assert(nr < I915_MAX_CONSTANT); if (nr) { + const float srgb_constants[4] = {1.0/1.055, 0.055/1.055, 2.4, 0.0822}; uint i; OUT_BATCH( _3DSTATE_PIXEL_SHADER_CONSTANTS | (nr * 4) ); @@ -340,9 +375,16 @@ emit_constants(struct i915_context *i915) c = (uint *) i915_buffer(i915->constants[PIPE_SHADER_FRAGMENT])->data; c += 4 * i; } - else { + else if (i < i915->fs->num_constants) { /* emit program constant */ c = (uint *) i915->fs->constants[i]; + } else { + /* emit constants for sRGB */ + + /* save const position in context for use in shader emit */ + i915->current.srgb_const_offset = i; + + c = (uint *) srgb_constants; } #if 0 /* debug */ { @@ -363,18 +405,74 @@ emit_constants(struct i915_context *i915) static void validate_program(struct i915_context *i915, unsigned *batch_space) { - uint additional_size = i915->current.target_fixup_format ? 1 : 0; + uint additional_size = 0, i; + + additional_size += i915->current.target_fixup_format ? 3 : 0; - /* we need more batch space if we want to emulate rgba framebuffers */ - *batch_space = i915->fs->decl_len + i915->fs->program_len + 3 * additional_size; + for (i = 0 ; i < i915->fs->program_len; i+=3) + if ( is_tex_instruction(i915->fs->program + i) && + i915->current.sampler_srgb[tex_sampler(i915->fs->program+i)] ) + additional_size += 3 * 8 /* 8 instructions for srgb emulation */; + + /* we need more batch space if we want to emulate rgba framebuffers + * or sRGB textures */ + *batch_space = i915->fs->decl_len + i915->fs->program_len + additional_size; +} + +static void emit_instruction(struct i915_context *i915, + int op, + int dst_mask, + int dst_reg, + int src0_reg, + int src1_reg, + int src2_reg) +{ + OUT_BATCH(op | + dst_mask | + 0 | /* saturate */ + A0_DEST(dst_reg) | + A0_SRC0(src0_reg) + ); + OUT_BATCH(A1_SRC0(src0_reg) | A1_SRC1(src1_reg)); + OUT_BATCH(A2_SRC1(src1_reg) | A2_SRC2(src2_reg)); +} + +static void +emit_srgb_fixup(struct i915_context *i915, + uint *program) +{ + int dst_reg = + (program[0] & UREG_TYPE_NR_MASK) >> UREG_A0_DEST_SHIFT_LEFT; + int dst_mask = program[0] & A0_DEST_CHANNEL_ALL; + int cst_idx = i915->current.srgb_const_offset; + int cst0_reg = swizzle(UREG(REG_TYPE_CONST, cst_idx), X, X, X, X); + int cst1_reg = swizzle(UREG(REG_TYPE_CONST, cst_idx), Y, Y, Y, Y); + int cst2_reg = swizzle(UREG(REG_TYPE_CONST, cst_idx), Z, Z, Z, Z); + int t1_reg = UREG(REG_TYPE_R, 1); + int t1x_reg = swizzle(UREG(REG_TYPE_R, 1), X, X, X, X); + int t1y_reg = swizzle(UREG(REG_TYPE_R, 1), Y, Y, Y, Y); + int t1z_reg = swizzle(UREG(REG_TYPE_R, 1), Z, Z, Z, Z); + + emit_instruction(i915, A0_MAD, A0_DEST_CHANNEL_ALL, t1_reg, dst_reg, cst0_reg, cst1_reg); + emit_instruction(i915, A0_LOG, A0_DEST_CHANNEL_X, t1_reg, t1x_reg, 0, 0); + emit_instruction(i915, A0_LOG, A0_DEST_CHANNEL_Y, t1_reg, t1y_reg, 0, 0); + emit_instruction(i915, A0_LOG, A0_DEST_CHANNEL_Z, t1_reg, t1z_reg, 0, 0); + emit_instruction(i915, A0_MUL, A0_DEST_CHANNEL_ALL, t1_reg, t1_reg, cst2_reg, 0); + emit_instruction(i915, A0_EXP, dst_mask & A0_DEST_CHANNEL_X, dst_reg, t1x_reg, 0, 0); + emit_instruction(i915, A0_EXP, dst_mask & A0_DEST_CHANNEL_Y, dst_reg, t1y_reg, 0, 0); + emit_instruction(i915, A0_EXP, dst_mask & A0_DEST_CHANNEL_Z, dst_reg, t1z_reg, 0, 0); } static void emit_program(struct i915_context *i915) { - uint need_target_fixup = i915->current.target_fixup_format ? 1 : 0; + uint additional_size = 0; uint i; + /* count how much additional space we'll need */ + validate_program(i915, &additional_size); + additional_size -= i915->fs->decl_len + i915->fs->program_len; + /* we should always have, at least, a pass-through program */ assert(i915->fs->program_len > 0); @@ -382,7 +480,7 @@ emit_program(struct i915_context *i915) { /* first word has the size, we have to adjust that */ uint size = (i915->fs->decl[0]); - size += need_target_fixup * 3; + size += additional_size; OUT_BATCH(size); } @@ -390,11 +488,21 @@ emit_program(struct i915_context *i915) OUT_BATCH(i915->fs->decl[i]); /* output the program */ - for (i = 0 ; i < i915->fs->program_len; i++) + assert(i915->fs->program_len % 3 == 0); + for (i = 0 ; i < i915->fs->program_len; i+=3) { OUT_BATCH(i915->fs->program[i]); + OUT_BATCH(i915->fs->program[i+1]); + OUT_BATCH(i915->fs->program[i+2]); + + /* TEX fixup for sRGB */ + if ( is_tex_instruction(i915->fs->program+i) && + i915->current.sampler_srgb[tex_sampler(i915->fs->program+i)] ) + emit_srgb_fixup(i915, i915->fs->program); + + } /* we emit an additional mov with swizzle to fake RGBA framebuffers */ - if (need_target_fixup) { + if (i915->current.target_fixup_format) { /* mov out_color, out_color.zyxw */ OUT_BATCH(A0_MOV | (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) | diff --git a/src/gallium/drivers/i915/i915_state_sampler.c b/src/gallium/drivers/i915/i915_state_sampler.c index 19d3c83ffcd..9aba68afbca 100644 --- a/src/gallium/drivers/i915/i915_state_sampler.c +++ b/src/gallium/drivers/i915/i915_state_sampler.c @@ -215,6 +215,7 @@ static uint translate_texture_format(enum pipe_format pipeFormat, case PIPE_FORMAT_B10G10R10A2_UNORM: return MAPSURF_32BIT | MT_32BIT_ARGB2101010; case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8A8_SRGB: return MAPSURF_32BIT | MT_32BIT_ARGB8888; case PIPE_FORMAT_B8G8R8X8_UNORM: return MAPSURF_32BIT | MT_32BIT_XRGB8888; @@ -309,6 +310,8 @@ static void update_map(struct i915_context *i915, assert(depth); format = translate_texture_format(pt->format, view); + i915->current.sampler_srgb[unit] = ( pt->format == PIPE_FORMAT_B8G8R8A8_SRGB || + pt->format == PIPE_FORMAT_L8_SRGB ); pitch = tex->stride; assert(format); diff --git a/src/gallium/drivers/i915/i915_state_static.c b/src/gallium/drivers/i915/i915_state_static.c index 9587dec4b90..4d020975576 100644 --- a/src/gallium/drivers/i915/i915_state_static.c +++ b/src/gallium/drivers/i915/i915_state_static.c @@ -31,7 +31,6 @@ #include "i915_screen.h" - /*********************************************************************** * Update framebuffer state */ @@ -39,6 +38,7 @@ static unsigned translate_format(enum pipe_format format) { switch (format) { case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8A8_SRGB: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_R8G8B8A8_UNORM: case PIPE_FORMAT_R8G8B8X8_UNORM: -- 2.30.2