#include "brw_state.h"
#include "brw_defines.h"
-#include "macros.h"
+#include "main/macros.h"
}
}
-
-static GLuint U_FIXED(GLfloat value, GLuint frac_bits)
-{
- value *= (1<<frac_bits);
- return value < 0 ? 0 : value;
-}
-
-static GLint S_FIXED(GLfloat value, GLuint frac_bits)
-{
- return value * (1<<frac_bits);
-}
-
-
-static GLuint upload_default_color( struct brw_context *brw,
- const GLfloat *color )
+static drm_intel_bo *upload_default_color( struct brw_context *brw,
+ const GLfloat *color )
{
struct brw_sampler_default_color sdc;
COPY_4V(sdc.color, color);
- return brw_cache_data( &brw->cache[BRW_SAMPLER_DEFAULT_COLOR], &sdc );
+ return brw_cache_data(&brw->cache, BRW_SAMPLER_DEFAULT_COLOR,
+ &sdc, sizeof(sdc));
}
-/*
+struct wm_sampler_key {
+ int sampler_count;
+
+ 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;
+
+ /** If target is cubemap, take context setting.
+ */
+ GLboolean seamless_cube_map;
+ } sampler[BRW_MAX_TEX_UNIT];
+};
+
+/**
+ * Sets the sampler state for a single unit based off of the sampler key
+ * entry.
*/
-static void brw_update_sampler_state( struct gl_texture_unit *texUnit,
- struct gl_texture_object *texObj,
- GLuint sdc_gs_offset,
- struct brw_sampler_state *sampler)
-{
- _mesa_memset(sampler, 0, sizeof(*sampler));
-
- switch (texObj->MinFilter) {
+static void brw_update_sampler_state(struct brw_context *brw,
+ struct wm_sampler_entry *key,
+ drm_intel_bo *sdc_bo,
+ struct brw_sampler_state *sampler)
+{
+ struct intel_context *intel = &brw->intel;
+
+ memset(sampler, 0, sizeof(*sampler));
+
+ switch (key->minfilter) {
case GL_NEAREST:
sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
/* Set Anisotropy:
*/
- if ( texObj->MaxAnisotropy > 1.0 ) {
+ if (key->max_aniso > 1.0) {
sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC;
sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
- if (texObj->MaxAnisotropy > 2.0) {
- sampler->ss3.max_aniso = MAX2((texObj->MaxAnisotropy - 2) / 2,
+ if (key->max_aniso > 2.0) {
+ sampler->ss3.max_aniso = MIN2((key->max_aniso - 2) / 2,
BRW_ANISORATIO_16);
}
}
else {
- switch (texObj->MagFilter) {
+ switch (key->magfilter) {
case GL_NEAREST:
sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
break;
}
}
- sampler->ss1.r_wrap_mode = translate_wrap_mode(texObj->WrapR);
- sampler->ss1.s_wrap_mode = translate_wrap_mode(texObj->WrapS);
- sampler->ss1.t_wrap_mode = translate_wrap_mode(texObj->WrapT);
+ 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);
- /* Fulsim complains if I don't do this. Hardware doesn't mind:
+ if (intel->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 0
- if (texObj->Target == GL_TEXTURE_CUBE_MAP_ARB) {
- sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
- sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
- sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
+ if (key->tex_target == GL_TEXTURE_CUBE_MAP) {
+ if (key->seamless_cube_map &&
+ (key->minfilter != GL_NEAREST || key->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;
+ } else {
+ sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ }
+ } else if (key->tex_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
+ * any nonexistent border pixels from floating in.
+ */
+ sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
}
-#endif
+
/* Set shadow function:
*/
- if (texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+ if (key->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(texObj->CompareFunc);
+ sampler->ss0.shadow_function =
+ intel_translate_shadow_compare_func(key->comparefunc);
}
/* Set LOD bias:
*/
- sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias + texObj->LodBias, -16, 15), 6);
+ sampler->ss0.lod_bias = S_FIXED(CLAMP(key->lod_bias, -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(MIN2(MAX2(texObj->MaxLod, 0), 13), 6);
- sampler->ss1.min_lod = U_FIXED(MIN2(MAX2(texObj->MinLod, 0), 13), 6);
+ 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_gs_offset >> 5;
+ sampler->ss2.default_color_pointer = sdc_bo->offset >> 5; /* reloc */
}
+/** 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;
+ char *last_entry_end = ((char*)&key->sampler_count) +
+ sizeof(key->sampler_count);
+
+ key->sampler_count = 0;
+
+ 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];
+
+ memset(last_entry_end, 0,
+ (char*)entry - last_entry_end + sizeof(*entry));
+ last_entry_end = ((char*)entry) + sizeof(*entry);
+
+ 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;
+
+ drm_intel_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;
+ }
+ }
+ struct wm_sampler_entry *entry = &key->sampler[key->sampler_count];
+ memset(last_entry_end, 0, (char*)entry - last_entry_end);
+}
/* All samplers must be uploaded in a single contiguous array, which
* complicates various things. However, this is still too confusing -
*/
static void upload_wm_samplers( struct brw_context *brw )
{
- GLuint unit;
- GLuint sampler_count = 0;
-
- /* _NEW_TEXTURE */
- for (unit = 0; unit < BRW_MAX_TEX_UNIT; unit++) {
- if (brw->attribs.Texture->Unit[unit]._ReallyEnabled) {
- struct gl_texture_unit *texUnit = &brw->attribs.Texture->Unit[unit];
- struct gl_texture_object *texObj = texUnit->_Current;
-
- GLuint sdc_gs_offset = upload_default_color(brw, texObj->BorderColor);
+ GLcontext *ctx = &brw->intel.ctx;
+ struct wm_sampler_key key;
+ int i, sampler_key_size;
- brw_update_sampler_state(texUnit,
- texObj,
- sdc_gs_offset,
- &brw->wm.sampler[unit]);
+ brw_wm_sampler_populate_key(brw, &key);
- sampler_count = unit + 1;
- }
- }
-
- if (brw->wm.sampler_count != sampler_count) {
- brw->wm.sampler_count = sampler_count;
+ if (brw->wm.sampler_count != key.sampler_count) {
+ brw->wm.sampler_count = key.sampler_count;
brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
}
- brw->wm.sampler_gs_offset = 0;
+ drm_intel_bo_unreference(brw->wm.sampler_bo);
+ brw->wm.sampler_bo = NULL;
+ if (brw->wm.sampler_count == 0)
+ return;
+
+ /* Only include the populated portion of the key in the search. */
+ sampler_key_size = offsetof(struct wm_sampler_key,
+ sampler[key.sampler_count]);
+ brw->wm.sampler_bo = brw_search_cache(&brw->cache, BRW_SAMPLER,
+ &key, sampler_key_size,
+ brw->wm.sdc_bo, key.sampler_count,
+ NULL);
+
+ /* 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];
- if (brw->wm.sampler_count)
- brw->wm.sampler_gs_offset =
- brw_cache_data_sz(&brw->cache[BRW_SAMPLER],
- brw->wm.sampler,
- sizeof(struct brw_sampler_state) * brw->wm.sampler_count);
-}
+ memset(sampler, 0, sizeof(sampler));
+ for (i = 0; i < key.sampler_count; i++) {
+ if (brw->wm.sdc_bo[i] == NULL)
+ continue;
+ brw_update_sampler_state(brw, &key.sampler[i], brw->wm.sdc_bo[i],
+ &sampler[i]);
+ }
+
+ brw->wm.sampler_bo = brw_upload_cache(&brw->cache, BRW_SAMPLER,
+ &key, sampler_key_size,
+ brw->wm.sdc_bo, key.sampler_count,
+ &sampler, sizeof(sampler));
+
+ /* Emit SDC relocations */
+ for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+ if (!ctx->Texture.Unit[i]._ReallyEnabled)
+ continue;
+
+ drm_intel_bo_emit_reloc(brw->wm.sampler_bo,
+ i * sizeof(struct brw_sampler_state) +
+ offsetof(struct brw_sampler_state, ss2),
+ brw->wm.sdc_bo[i], 0,
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ }
+ }
+}
const struct brw_tracked_state brw_wm_samplers = {
.dirty = {
.brw = 0,
.cache = 0
},
- .update = upload_wm_samplers
+ .prepare = upload_wm_samplers,
};