#include "brw_defines.h"
#include "main/macros.h"
-
+#include "main/samplerobj.h"
/* Samplers aren't strictly wm state from the hardware's perspective,
-/* The brw (and related graphics cores) do not support GL_CLAMP. The
- * Intel drivers for "other operating systems" implement GL_CLAMP as
- * GL_CLAMP_TO_EDGE, so the same is done here.
- */
-static GLuint translate_wrap_mode( GLenum wrap )
+uint32_t
+translate_wrap_mode(GLenum wrap, bool using_nearest)
{
switch( wrap ) {
case GL_REPEAT:
return BRW_TEXCOORDMODE_WRAP;
- case GL_CLAMP:
- return BRW_TEXCOORDMODE_CLAMP;
+ case GL_CLAMP:
+ /* GL_CLAMP is the weird mode where coordinates are clamped to
+ * [0.0, 1.0], so linear filtering of coordinates outside of
+ * [0.0, 1.0] give you half edge texel value and half border
+ * color. The fragment shader will clamp the coordinates, and
+ * we set clamp_border here, which gets the result desired. We
+ * just use clamp(_to_edge) for nearest, because for nearest
+ * clamping to 1.0 gives border color instead of the desired
+ * edge texels.
+ */
+ if (using_nearest)
+ return BRW_TEXCOORDMODE_CLAMP;
+ else
+ return BRW_TEXCOORDMODE_CLAMP_BORDER;
case GL_CLAMP_TO_EDGE:
- return BRW_TEXCOORDMODE_CLAMP; /* conform likes it this way */
+ return BRW_TEXCOORDMODE_CLAMP;
case GL_CLAMP_TO_BORDER:
return BRW_TEXCOORDMODE_CLAMP_BORDER;
case GL_MIRRORED_REPEAT:
}
}
-static dri_bo *upload_default_color( struct brw_context *brw,
- const GLfloat *color )
+/**
+ * Upload SAMPLER_BORDER_COLOR_STATE.
+ */
+void
+upload_default_color(struct brw_context *brw,
+ struct gl_sampler_object *sampler,
+ int unit,
+ uint32_t *sdc_offset)
{
- struct brw_sampler_default_color sdc;
+ struct gl_context *ctx = &brw->ctx;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *texObj = texUnit->_Current;
+ struct gl_texture_image *firstImage = texObj->Image[0][texObj->BaseLevel];
+ float color[4];
+
+ switch (firstImage->_BaseFormat) {
+ case GL_DEPTH_COMPONENT:
+ /* GL specs that border color for depth textures is taken from the
+ * R channel, while the hardware uses A. Spam R into all the
+ * channels for safety.
+ */
+ color[0] = sampler->BorderColor.f[0];
+ color[1] = sampler->BorderColor.f[0];
+ color[2] = sampler->BorderColor.f[0];
+ color[3] = sampler->BorderColor.f[0];
+ break;
+ case GL_ALPHA:
+ color[0] = 0.0;
+ color[1] = 0.0;
+ color[2] = 0.0;
+ color[3] = sampler->BorderColor.f[3];
+ break;
+ case GL_INTENSITY:
+ color[0] = sampler->BorderColor.f[0];
+ color[1] = sampler->BorderColor.f[0];
+ color[2] = sampler->BorderColor.f[0];
+ color[3] = sampler->BorderColor.f[0];
+ break;
+ case GL_LUMINANCE:
+ color[0] = sampler->BorderColor.f[0];
+ color[1] = sampler->BorderColor.f[0];
+ color[2] = sampler->BorderColor.f[0];
+ color[3] = 1.0;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ color[0] = sampler->BorderColor.f[0];
+ color[1] = sampler->BorderColor.f[0];
+ color[2] = sampler->BorderColor.f[0];
+ color[3] = sampler->BorderColor.f[3];
+ break;
+ default:
+ color[0] = sampler->BorderColor.f[0];
+ color[1] = sampler->BorderColor.f[1];
+ color[2] = sampler->BorderColor.f[2];
+ color[3] = sampler->BorderColor.f[3];
+ break;
+ }
- COPY_4V(sdc.color, color);
-
- return brw_cache_data(&brw->cache, BRW_SAMPLER_DEFAULT_COLOR,
- &sdc, sizeof(sdc), NULL, 0);
-}
+ /* In some cases we use an RGBA surface format for GL RGB textures,
+ * where we've initialized the A channel to 1.0. We also have to set
+ * the border color alpha to 1.0 in that case.
+ */
+ if (firstImage->_BaseFormat == GL_RGB)
+ color[3] = 1.0;
+ if (brw->gen == 5 || brw->gen == 6) {
+ struct gen5_sampler_default_color *sdc;
-struct wm_sampler_key {
- int sampler_count;
+ sdc = brw_state_batch(brw, AUB_TRACE_SAMPLER_DEFAULT_COLOR,
+ sizeof(*sdc), 32, sdc_offset);
- struct wm_sampler_entry {
- GLenum tex_target;
- GLenum wrap_r, wrap_s, wrap_t;
- float maxlod, minlod;
- float lod_bias;
- float max_aniso;
- GLenum minfilter, magfilter;
- GLenum comparemode, comparefunc;
- dri_bo *sdc_bo;
+ memset(sdc, 0, sizeof(*sdc));
- /** If target is cubemap, take context setting.
- */
- GLboolean seamless_cube_map;
- } sampler[BRW_MAX_TEX_UNIT];
-};
+ UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[0], color[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[1], color[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[2], color[2]);
+ UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[3], color[3]);
+
+ UNCLAMPED_FLOAT_TO_USHORT(sdc->us[0], color[0]);
+ UNCLAMPED_FLOAT_TO_USHORT(sdc->us[1], color[1]);
+ UNCLAMPED_FLOAT_TO_USHORT(sdc->us[2], color[2]);
+ UNCLAMPED_FLOAT_TO_USHORT(sdc->us[3], color[3]);
+
+ UNCLAMPED_FLOAT_TO_SHORT(sdc->s[0], color[0]);
+ UNCLAMPED_FLOAT_TO_SHORT(sdc->s[1], color[1]);
+ UNCLAMPED_FLOAT_TO_SHORT(sdc->s[2], color[2]);
+ UNCLAMPED_FLOAT_TO_SHORT(sdc->s[3], color[3]);
+
+ sdc->hf[0] = _mesa_float_to_half(color[0]);
+ sdc->hf[1] = _mesa_float_to_half(color[1]);
+ sdc->hf[2] = _mesa_float_to_half(color[2]);
+ sdc->hf[3] = _mesa_float_to_half(color[3]);
+
+ sdc->b[0] = sdc->s[0] >> 8;
+ sdc->b[1] = sdc->s[1] >> 8;
+ sdc->b[2] = sdc->s[2] >> 8;
+ sdc->b[3] = sdc->s[3] >> 8;
+
+ sdc->f[0] = color[0];
+ sdc->f[1] = color[1];
+ sdc->f[2] = color[2];
+ sdc->f[3] = color[3];
+ } else {
+ struct brw_sampler_default_color *sdc;
+
+ sdc = brw_state_batch(brw, AUB_TRACE_SAMPLER_DEFAULT_COLOR,
+ sizeof(*sdc), 32, sdc_offset);
+
+ COPY_4V(sdc->color, color);
+ }
+}
/**
* Sets the sampler state for a single unit based off of the sampler key
* entry.
*/
-static void brw_update_sampler_state(struct wm_sampler_entry *key,
- dri_bo *sdc_bo,
- struct brw_sampler_state *sampler)
+static void brw_update_sampler_state(struct brw_context *brw,
+ int unit,
+ int ss_index,
+ struct brw_sampler_state *sampler,
+ uint32_t sampler_state_table_offset,
+ uint32_t *sdc_offset)
{
- _mesa_memset(sampler, 0, sizeof(*sampler));
+ struct gl_context *ctx = &brw->ctx;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *texObj = texUnit->_Current;
+ struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit);
+ bool using_nearest = false;
+
+ /* These don't use samplers at all. */
+ if (texObj->Target == GL_TEXTURE_BUFFER)
+ return;
- switch (key->minfilter) {
+ switch (gl_sampler->MinFilter) {
case GL_NEAREST:
sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
+ using_nearest = true;
break;
case GL_LINEAR:
sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
/* Set Anisotropy:
*/
- if (key->max_aniso > 1.0) {
+ if (gl_sampler->MaxAnisotropy > 1.0) {
sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC;
sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
- if (key->max_aniso > 2.0) {
- sampler->ss3.max_aniso = MIN2((key->max_aniso - 2) / 2,
+ if (gl_sampler->MaxAnisotropy > 2.0) {
+ sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2,
BRW_ANISORATIO_16);
}
}
else {
- switch (key->magfilter) {
+ switch (gl_sampler->MagFilter) {
case GL_NEAREST:
sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
+ using_nearest = true;
break;
case GL_LINEAR:
sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
}
}
- sampler->ss1.r_wrap_mode = translate_wrap_mode(key->wrap_r);
- sampler->ss1.s_wrap_mode = translate_wrap_mode(key->wrap_s);
- sampler->ss1.t_wrap_mode = translate_wrap_mode(key->wrap_t);
+ sampler->ss1.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR,
+ using_nearest);
+ sampler->ss1.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS,
+ using_nearest);
+ sampler->ss1.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT,
+ using_nearest);
+
+ if (brw->gen >= 6 &&
+ sampler->ss0.min_filter != sampler->ss0.mag_filter)
+ sampler->ss0.min_mag_neq = 1;
/* Cube-maps on 965 and later must use the same wrap mode for all 3
* coordinate dimensions. Futher, only CUBE and CLAMP are valid.
*/
- if (key->tex_target == GL_TEXTURE_CUBE_MAP) {
- if (key->seamless_cube_map &&
- (key->minfilter != GL_NEAREST || key->magfilter != GL_NEAREST)) {
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP ||
+ texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) {
+ if (ctx->Texture.CubeMapSeamless &&
+ (gl_sampler->MinFilter != GL_NEAREST ||
+ gl_sampler->MagFilter != GL_NEAREST)) {
sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
}
- } else if (key->tex_target == GL_TEXTURE_1D) {
+ } else if (texObj->Target == GL_TEXTURE_1D) {
/* There's a bug in 1D texture sampling - it actually pays
* attention to the wrap_t value, though it should not.
* Override the wrap_t value here to GL_REPEAT to keep
/* Set shadow function:
*/
- if (key->comparemode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+ if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
/* Shadowing is "enabled" by emitting a particular sampler
* message (sample_c). So need to recompile WM program when
* shadow comparison is enabled on each/any texture unit.
*/
sampler->ss0.shadow_function =
- intel_translate_shadow_compare_func(key->comparefunc);
+ intel_translate_shadow_compare_func(gl_sampler->CompareFunc);
}
/* Set LOD bias:
*/
- sampler->ss0.lod_bias = S_FIXED(CLAMP(key->lod_bias, -16, 15), 6);
+ sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias +
+ gl_sampler->LodBias, -16, 15), 6);
sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
*/
sampler->ss0.base_level = U_FIXED(0, 1);
- sampler->ss1.max_lod = U_FIXED(CLAMP(key->maxlod, 0, 13), 6);
- sampler->ss1.min_lod = U_FIXED(CLAMP(key->minlod, 0, 13), 6);
-
- sampler->ss2.default_color_pointer = sdc_bo->offset >> 5; /* reloc */
-}
+ sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 6);
+ sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 6);
+ /* On Gen6+, the sampler can handle non-normalized texture
+ * rectangle coordinates natively
+ */
+ if (brw->gen >= 6 && texObj->Target == GL_TEXTURE_RECTANGLE) {
+ sampler->ss3.non_normalized_coord = 1;
+ }
-/** Sets up the cache key for sampler state for all texture units */
-static void
-brw_wm_sampler_populate_key(struct brw_context *brw,
- struct wm_sampler_key *key)
-{
- GLcontext *ctx = &brw->intel.ctx;
- int unit;
-
- memset(key, 0, sizeof(*key));
-
- for (unit = 0; unit < BRW_MAX_TEX_UNIT; unit++) {
- if (ctx->Texture.Unit[unit]._ReallyEnabled) {
- struct wm_sampler_entry *entry = &key->sampler[unit];
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- struct gl_texture_object *texObj = texUnit->_Current;
- struct intel_texture_object *intelObj = intel_texture_object(texObj);
- struct gl_texture_image *firstImage =
- texObj->Image[0][intelObj->firstLevel];
-
- entry->tex_target = texObj->Target;
-
- entry->seamless_cube_map = (texObj->Target == GL_TEXTURE_CUBE_MAP)
- ? ctx->Texture.CubeMapSeamless : GL_FALSE;
-
- entry->wrap_r = texObj->WrapR;
- entry->wrap_s = texObj->WrapS;
- entry->wrap_t = texObj->WrapT;
-
- entry->maxlod = texObj->MaxLod;
- entry->minlod = texObj->MinLod;
- entry->lod_bias = texUnit->LodBias + texObj->LodBias;
- entry->max_aniso = texObj->MaxAnisotropy;
- entry->minfilter = texObj->MinFilter;
- entry->magfilter = texObj->MagFilter;
- entry->comparemode = texObj->CompareMode;
- entry->comparefunc = texObj->CompareFunc;
-
- dri_bo_unreference(brw->wm.sdc_bo[unit]);
- if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) {
- float bordercolor[4] = {
- texObj->BorderColor.f[0],
- texObj->BorderColor.f[0],
- texObj->BorderColor.f[0],
- texObj->BorderColor.f[0]
- };
- /* GL specs that border color for depth textures is taken from the
- * R channel, while the hardware uses A. Spam R into all the
- * channels for safety.
- */
- brw->wm.sdc_bo[unit] = upload_default_color(brw, bordercolor);
- } else {
- brw->wm.sdc_bo[unit] = upload_default_color(brw,
- texObj->BorderColor.f);
- }
- key->sampler_count = unit + 1;
- }
+ upload_default_color(brw, gl_sampler, unit, sdc_offset);
+
+ if (brw->gen >= 6) {
+ sampler->ss2.default_color_pointer = *sdc_offset >> 5;
+ } else {
+ /* reloc */
+ sampler->ss2.default_color_pointer = (brw->batch.bo->offset +
+ *sdc_offset) >> 5;
+
+ drm_intel_bo_emit_reloc(brw->batch.bo,
+ sampler_state_table_offset +
+ ss_index * sizeof(struct brw_sampler_state) +
+ offsetof(struct brw_sampler_state, ss2),
+ brw->batch.bo, *sdc_offset,
+ I915_GEM_DOMAIN_SAMPLER, 0);
}
+
+ if (sampler->ss0.min_filter != BRW_MAPFILTER_NEAREST)
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MIN;
+ if (sampler->ss0.mag_filter != BRW_MAPFILTER_NEAREST)
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MAG;
}
-/* All samplers must be uploaded in a single contiguous array, which
- * complicates various things. However, this is still too confusing -
- * FIXME: simplify all the different new texture state flags.
- */
-static void upload_wm_samplers( struct brw_context *brw )
-{
- GLcontext *ctx = &brw->intel.ctx;
- struct wm_sampler_key key;
- int i;
- brw_wm_sampler_populate_key(brw, &key);
+static void
+brw_upload_sampler_state_table(struct brw_context *brw,
+ struct gl_program *prog,
+ uint32_t sampler_count,
+ uint32_t *sst_offset,
+ uint32_t *sdc_offset)
+{
+ struct gl_context *ctx = &brw->ctx;
+ struct brw_sampler_state *samplers;
- if (brw->wm.sampler_count != key.sampler_count) {
- brw->wm.sampler_count = key.sampler_count;
- brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
- }
+ GLbitfield SamplersUsed = prog->SamplersUsed;
- dri_bo_unreference(brw->wm.sampler_bo);
- brw->wm.sampler_bo = NULL;
- if (brw->wm.sampler_count == 0)
+ if (sampler_count == 0)
return;
- brw->wm.sampler_bo = brw_search_cache(&brw->cache, BRW_SAMPLER,
- &key, sizeof(key),
- brw->wm.sdc_bo, key.sampler_count,
- NULL);
+ samplers = brw_state_batch(brw, AUB_TRACE_SAMPLER_STATE,
+ sampler_count * sizeof(*samplers),
+ 32, sst_offset);
+ memset(samplers, 0, sampler_count * sizeof(*samplers));
+
+ for (unsigned s = 0; s < sampler_count; s++) {
+ if (SamplersUsed & (1 << s)) {
+ const unsigned unit = prog->SamplerUnits[s];
+ if (ctx->Texture.Unit[unit]._ReallyEnabled)
+ brw_update_sampler_state(brw, unit, s, &samplers[s],
+ *sst_offset, &sdc_offset[s]);
+ }
+ }
- /* If we didnt find it in the cache, compute the state and put it in the
- * cache.
- */
- if (brw->wm.sampler_bo == NULL) {
- struct brw_sampler_state sampler[BRW_MAX_TEX_UNIT];
+ brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
+}
- memset(sampler, 0, sizeof(sampler));
- for (i = 0; i < key.sampler_count; i++) {
- if (brw->wm.sdc_bo[i] == NULL)
- continue;
+static void
+brw_upload_fs_samplers(struct brw_context *brw)
+{
+ /* BRW_NEW_FRAGMENT_PROGRAM */
+ struct gl_program *fs = (struct gl_program *) brw->fragment_program;
+ brw->vtbl.upload_sampler_state_table(brw, fs,
+ brw->wm.sampler_count,
+ &brw->wm.sampler_offset,
+ brw->wm.sdc_offset);
+}
- brw_update_sampler_state(&key.sampler[i], brw->wm.sdc_bo[i],
- &sampler[i]);
- }
+const struct brw_tracked_state brw_fs_samplers = {
+ .dirty = {
+ .mesa = _NEW_TEXTURE,
+ .brw = BRW_NEW_BATCH |
+ BRW_NEW_FRAGMENT_PROGRAM,
+ .cache = 0
+ },
+ .emit = brw_upload_fs_samplers,
+};
- brw->wm.sampler_bo = brw_upload_cache(&brw->cache, BRW_SAMPLER,
- &key, sizeof(key),
- brw->wm.sdc_bo, key.sampler_count,
- &sampler, sizeof(sampler),
- NULL, NULL);
-
- /* Emit SDC relocations */
- for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
- if (!ctx->Texture.Unit[i]._ReallyEnabled)
- continue;
-
- dri_bo_emit_reloc(brw->wm.sampler_bo,
- I915_GEM_DOMAIN_SAMPLER, 0,
- 0,
- i * sizeof(struct brw_sampler_state) +
- offsetof(struct brw_sampler_state, ss2),
- brw->wm.sdc_bo[i]);
- }
- }
+static void
+brw_upload_vs_samplers(struct brw_context *brw)
+{
+ /* BRW_NEW_VERTEX_PROGRAM */
+ struct gl_program *vs = (struct gl_program *) brw->vertex_program;
+ brw->vtbl.upload_sampler_state_table(brw, vs,
+ brw->vs.sampler_count,
+ &brw->vs.sampler_offset,
+ brw->vs.sdc_offset);
}
-const struct brw_tracked_state brw_wm_samplers = {
+
+const struct brw_tracked_state brw_vs_samplers = {
.dirty = {
.mesa = _NEW_TEXTURE,
- .brw = 0,
+ .brw = BRW_NEW_BATCH |
+ BRW_NEW_VERTEX_PROGRAM,
.cache = 0
},
- .prepare = upload_wm_samplers,
+ .emit = brw_upload_vs_samplers,
};
+void
+gen4_init_vtable_sampler_functions(struct brw_context *brw)
+{
+ brw->vtbl.upload_sampler_state_table = brw_upload_sampler_state_table;
+}