0,0 → 1,361 |
/********************************************************** |
* Copyright 2008-2009 VMware, Inc. 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 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 AUTHORS OR COPYRIGHT HOLDERS |
* 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 "util/u_inlines.h" |
#include "util/u_memory.h" |
#include "pipe/p_defines.h" |
#include "util/u_math.h" |
|
#include "svga_sampler_view.h" |
#include "svga_winsys.h" |
#include "svga_context.h" |
#include "svga_state.h" |
#include "svga_cmd.h" |
|
|
void svga_cleanup_tss_binding(struct svga_context *svga) |
{ |
unsigned i; |
unsigned count = MAX2( svga->curr.num_sampler_views, |
svga->state.hw_draw.num_views ); |
|
for (i = 0; i < count; i++) { |
struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; |
|
svga_sampler_view_reference(&view->v, NULL); |
pipe_sampler_view_release(&svga->pipe, &svga->curr.sampler_views[i]); |
pipe_resource_reference( &view->texture, NULL ); |
|
view->dirty = 1; |
} |
} |
|
|
struct bind_queue { |
struct { |
unsigned unit; |
struct svga_hw_view_state *view; |
} bind[PIPE_MAX_SAMPLERS]; |
|
unsigned bind_count; |
}; |
|
|
static enum pipe_error |
update_tss_binding(struct svga_context *svga, |
unsigned dirty ) |
{ |
boolean reemit = svga->rebind.texture_samplers; |
unsigned i; |
unsigned count = MAX2( svga->curr.num_sampler_views, |
svga->state.hw_draw.num_views ); |
unsigned min_lod; |
unsigned max_lod; |
|
struct bind_queue queue; |
|
queue.bind_count = 0; |
|
for (i = 0; i < count; i++) { |
const struct svga_sampler_state *s = svga->curr.sampler[i]; |
struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; |
struct pipe_resource *texture = NULL; |
struct pipe_sampler_view *sv = svga->curr.sampler_views[i]; |
|
/* get min max lod */ |
if (sv) { |
min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level)); |
max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, |
sv->texture->last_level); |
texture = sv->texture; |
} else { |
min_lod = 0; |
max_lod = 0; |
} |
|
if (view->texture != texture || |
view->min_lod != min_lod || |
view->max_lod != max_lod) { |
|
svga_sampler_view_reference(&view->v, NULL); |
pipe_resource_reference( &view->texture, texture ); |
|
view->dirty = TRUE; |
view->min_lod = min_lod; |
view->max_lod = max_lod; |
|
if (texture) |
view->v = svga_get_tex_sampler_view(&svga->pipe, |
texture, |
min_lod, |
max_lod); |
} |
|
/* |
* We need to reemit non-null texture bindings, even when they are not |
* dirty, to ensure that the resources are paged in. |
*/ |
|
if (view->dirty || |
(reemit && view->v)) { |
queue.bind[queue.bind_count].unit = i; |
queue.bind[queue.bind_count].view = view; |
queue.bind_count++; |
} |
if (!view->dirty && view->v) { |
svga_validate_sampler_view(svga, view->v); |
} |
} |
|
svga->state.hw_draw.num_views = svga->curr.num_sampler_views; |
|
if (queue.bind_count) { |
SVGA3dTextureState *ts; |
|
if (SVGA3D_BeginSetTextureState( svga->swc, |
&ts, |
queue.bind_count ) != PIPE_OK) |
goto fail; |
|
for (i = 0; i < queue.bind_count; i++) { |
struct svga_winsys_surface *handle; |
|
ts[i].stage = queue.bind[i].unit; |
ts[i].name = SVGA3D_TS_BIND_TEXTURE; |
|
if (queue.bind[i].view->v) { |
handle = queue.bind[i].view->v->handle; |
} |
else { |
handle = NULL; |
} |
svga->swc->surface_relocation(svga->swc, |
&ts[i].value, |
handle, |
SVGA_RELOC_READ); |
|
queue.bind[i].view->dirty = FALSE; |
} |
|
SVGA_FIFOCommitAll( svga->swc ); |
} |
|
svga->rebind.texture_samplers = FALSE; |
|
return 0; |
|
fail: |
return PIPE_ERROR_OUT_OF_MEMORY; |
} |
|
|
/* |
* Rebind textures. |
* |
* Similar to update_tss_binding, but without any state checking/update. |
* |
* Called at the beginning of every new command buffer to ensure that |
* non-dirty textures are properly paged-in. |
*/ |
enum pipe_error |
svga_reemit_tss_bindings(struct svga_context *svga) |
{ |
unsigned i; |
enum pipe_error ret; |
struct bind_queue queue; |
|
assert(svga->rebind.texture_samplers); |
|
queue.bind_count = 0; |
|
for (i = 0; i < svga->state.hw_draw.num_views; i++) { |
struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; |
|
if (view->v) { |
queue.bind[queue.bind_count].unit = i; |
queue.bind[queue.bind_count].view = view; |
queue.bind_count++; |
} |
} |
|
if (queue.bind_count) { |
SVGA3dTextureState *ts; |
|
ret = SVGA3D_BeginSetTextureState(svga->swc, |
&ts, |
queue.bind_count); |
if (ret != PIPE_OK) { |
return ret; |
} |
|
for (i = 0; i < queue.bind_count; i++) { |
struct svga_winsys_surface *handle; |
|
ts[i].stage = queue.bind[i].unit; |
ts[i].name = SVGA3D_TS_BIND_TEXTURE; |
|
assert(queue.bind[i].view->v); |
handle = queue.bind[i].view->v->handle; |
svga->swc->surface_relocation(svga->swc, |
&ts[i].value, |
handle, |
SVGA_RELOC_READ); |
} |
|
SVGA_FIFOCommitAll(svga->swc); |
} |
|
svga->rebind.texture_samplers = FALSE; |
|
return PIPE_OK; |
} |
|
|
struct svga_tracked_state svga_hw_tss_binding = { |
"texture binding emit", |
SVGA_NEW_TEXTURE_BINDING | |
SVGA_NEW_SAMPLER, |
update_tss_binding |
}; |
|
|
/*********************************************************************** |
*/ |
|
struct ts_queue { |
unsigned ts_count; |
SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX]; |
}; |
|
|
#define EMIT_TS(svga, unit, val, token, fail) \ |
do { \ |
assert(unit < Elements(svga->state.hw_draw.ts)); \ |
assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ |
if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ |
svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ |
svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ |
} \ |
} while (0) |
|
#define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail) \ |
do { \ |
unsigned val = fui(fvalue); \ |
assert(unit < Elements(svga->state.hw_draw.ts)); \ |
assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ |
if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ |
svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ |
svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ |
} \ |
} while (0) |
|
|
static INLINE void |
svga_queue_tss( struct ts_queue *q, |
unsigned unit, |
unsigned tss, |
unsigned value ) |
{ |
assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0])); |
q->ts[q->ts_count].stage = unit; |
q->ts[q->ts_count].name = tss; |
q->ts[q->ts_count].value = value; |
q->ts_count++; |
} |
|
|
static enum pipe_error |
update_tss(struct svga_context *svga, |
unsigned dirty ) |
{ |
unsigned i; |
struct ts_queue queue; |
|
queue.ts_count = 0; |
for (i = 0; i < svga->curr.num_samplers; i++) { |
if (svga->curr.sampler[i]) { |
const struct svga_sampler_state *curr = svga->curr.sampler[i]; |
|
EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail); |
EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail); |
EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail); |
EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail); |
EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail); |
EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail); |
EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail); |
EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail); |
EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail); |
// TEXCOORDINDEX -- hopefully not needed |
|
if (svga->curr.tex_flags.flag_1d & (1 << i)) { |
EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail); |
} |
else |
EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail); |
|
if (svga->curr.tex_flags.flag_srgb & (1 << i)) |
EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail); |
else |
EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail); |
|
} |
} |
|
if (queue.ts_count) { |
SVGA3dTextureState *ts; |
|
if (SVGA3D_BeginSetTextureState( svga->swc, |
&ts, |
queue.ts_count ) != PIPE_OK) |
goto fail; |
|
memcpy( ts, |
queue.ts, |
queue.ts_count * sizeof queue.ts[0]); |
|
SVGA_FIFOCommitAll( svga->swc ); |
} |
|
return PIPE_OK; |
|
fail: |
/* XXX: need to poison cached hardware state on failure to ensure |
* dirty state gets re-emitted. Fix this by re-instating partial |
* FIFOCommit command and only updating cached hw state once the |
* initial allocation has succeeded. |
*/ |
memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts)); |
|
return PIPE_ERROR_OUT_OF_MEMORY; |
} |
|
|
struct svga_tracked_state svga_hw_tss = { |
"texture state emit", |
(SVGA_NEW_SAMPLER | |
SVGA_NEW_TEXTURE_FLAGS), |
update_tss |
}; |
|