/**********************************************************
|
* 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_bitmask.h"
|
#include "util/u_debug.h"
|
#include "pipe/p_defines.h"
|
#include "util/u_memory.h"
|
#include "draw/draw_context.h"
|
|
#include "svga_context.h"
|
#include "svga_screen.h"
|
#include "svga_state.h"
|
#include "svga_draw.h"
|
#include "svga_cmd.h"
|
#include "svga_hw_reg.h"
|
|
/* This is just enough to decide whether we need to use the draw
|
* module (swtnl) or not.
|
*/
|
static const struct svga_tracked_state *need_swtnl_state[] =
|
{
|
&svga_update_need_swvfetch,
|
&svga_update_need_pipeline,
|
&svga_update_need_swtnl,
|
NULL
|
};
|
|
|
/* Atoms to update hardware state prior to emitting a clear or draw
|
* packet.
|
*/
|
static const struct svga_tracked_state *hw_clear_state[] =
|
{
|
&svga_hw_scissor,
|
&svga_hw_viewport,
|
&svga_hw_framebuffer,
|
NULL
|
};
|
|
|
/* Atoms to update hardware state prior to emitting a draw packet.
|
*/
|
static const struct svga_tracked_state *hw_draw_state[] =
|
{
|
&svga_need_tgsi_transform,
|
&svga_hw_fs,
|
&svga_hw_gs,
|
&svga_hw_vs,
|
&svga_hw_rss,
|
&svga_hw_sampler, /* VGPU10 */
|
&svga_hw_sampler_bindings, /* VGPU10 */
|
&svga_hw_tss, /* pre-VGPU10 */
|
&svga_hw_tss_binding, /* pre-VGPU10 */
|
&svga_hw_clip_planes,
|
&svga_hw_vdecl,
|
&svga_hw_fs_constants,
|
&svga_hw_gs_constants,
|
&svga_hw_vs_constants,
|
NULL
|
};
|
|
|
static const struct svga_tracked_state *swtnl_draw_state[] =
|
{
|
&svga_update_swtnl_draw,
|
&svga_update_swtnl_vdecl,
|
NULL
|
};
|
|
/* Flattens the graph of state dependencies. Could swap the positions
|
* of hw_clear_state and need_swtnl_state without breaking anything.
|
*/
|
static const struct svga_tracked_state **state_levels[] =
|
{
|
need_swtnl_state,
|
hw_clear_state,
|
hw_draw_state,
|
swtnl_draw_state
|
};
|
|
|
|
static unsigned
|
check_state(unsigned a, unsigned b)
|
{
|
return (a & b);
|
}
|
|
static void
|
accumulate_state(unsigned *a, unsigned b)
|
{
|
*a |= b;
|
}
|
|
|
static void
|
xor_states(unsigned *result, unsigned a, unsigned b)
|
{
|
*result = a ^ b;
|
}
|
|
|
static enum pipe_error
|
update_state(struct svga_context *svga,
|
const struct svga_tracked_state *atoms[],
|
unsigned *state)
|
{
|
#ifdef DEBUG
|
boolean debug = TRUE;
|
#else
|
boolean debug = FALSE;
|
#endif
|
enum pipe_error ret = PIPE_OK;
|
unsigned i;
|
|
ret = svga_hwtnl_flush( svga->hwtnl );
|
if (ret != PIPE_OK)
|
return ret;
|
|
if (debug) {
|
/* Debug version which enforces various sanity checks on the
|
* state flags which are generated and checked to help ensure
|
* state atoms are ordered correctly in the list.
|
*/
|
unsigned examined, prev;
|
|
examined = 0;
|
prev = *state;
|
|
for (i = 0; atoms[i] != NULL; i++) {
|
unsigned generated;
|
|
assert(atoms[i]->dirty);
|
assert(atoms[i]->update);
|
|
if (check_state(*state, atoms[i]->dirty)) {
|
if (0)
|
debug_printf("update: %s\n", atoms[i]->name);
|
ret = atoms[i]->update( svga, *state );
|
if (ret != PIPE_OK)
|
return ret;
|
}
|
|
/* generated = (prev ^ state)
|
* if (examined & generated)
|
* fail;
|
*/
|
xor_states(&generated, prev, *state);
|
if (check_state(examined, generated)) {
|
debug_printf("state atom %s generated state already examined\n",
|
atoms[i]->name);
|
assert(0);
|
}
|
|
prev = *state;
|
accumulate_state(&examined, atoms[i]->dirty);
|
}
|
}
|
else {
|
for (i = 0; atoms[i] != NULL; i++) {
|
if (check_state(*state, atoms[i]->dirty)) {
|
ret = atoms[i]->update( svga, *state );
|
if (ret != PIPE_OK)
|
return ret;
|
}
|
}
|
}
|
|
return PIPE_OK;
|
}
|
|
|
enum pipe_error
|
svga_update_state(struct svga_context *svga, unsigned max_level)
|
{
|
struct svga_screen *screen = svga_screen(svga->pipe.screen);
|
enum pipe_error ret = PIPE_OK;
|
unsigned i;
|
|
SVGA_STATS_TIME_PUSH(screen->sws, SVGA_STATS_TIME_UPDATESTATE);
|
|
/* Check for updates to bound textures. This can't be done in an
|
* atom as there is no flag which could provoke this test, and we
|
* cannot create one.
|
*/
|
if (svga->state.texture_timestamp != screen->texture_timestamp) {
|
svga->state.texture_timestamp = screen->texture_timestamp;
|
svga->dirty |= SVGA_NEW_TEXTURE;
|
}
|
|
for (i = 0; i <= max_level; i++) {
|
svga->dirty |= svga->state.dirty[i];
|
|
if (svga->dirty) {
|
ret = update_state( svga,
|
state_levels[i],
|
&svga->dirty );
|
if (ret != PIPE_OK)
|
goto done;
|
|
svga->state.dirty[i] = 0;
|
}
|
}
|
|
for (; i < SVGA_STATE_MAX; i++)
|
svga->state.dirty[i] |= svga->dirty;
|
|
svga->dirty = 0;
|
|
svga->hud.num_validations++;
|
|
done:
|
SVGA_STATS_TIME_POP(screen->sws);
|
return ret;
|
}
|
|
|
void
|
svga_update_state_retry(struct svga_context *svga, unsigned max_level)
|
{
|
enum pipe_error ret;
|
|
ret = svga_update_state( svga, max_level );
|
|
if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
|
svga_context_flush(svga, NULL);
|
ret = svga_update_state( svga, max_level );
|
}
|
|
assert( ret == PIPE_OK );
|
}
|
|
|
|
#define EMIT_RS(_rs, _count, _name, _value) \
|
do { \
|
_rs[_count].state = _name; \
|
_rs[_count].uintValue = _value; \
|
_count++; \
|
} while (0)
|
|
|
/* Setup any hardware state which will be constant through the life of
|
* a context.
|
*/
|
enum pipe_error
|
svga_emit_initial_state(struct svga_context *svga)
|
{
|
if (svga_have_vgpu10(svga)) {
|
SVGA3dRasterizerStateId id = util_bitmask_add(svga->rast_object_id_bm);
|
enum pipe_error ret;
|
|
/* XXX preliminary code */
|
ret = SVGA3D_vgpu10_DefineRasterizerState(svga->swc,
|
id,
|
SVGA3D_FILLMODE_FILL,
|
SVGA3D_CULL_NONE,
|
1, /* frontCounterClockwise */
|
0, /* depthBias */
|
0.0f, /* depthBiasClamp */
|
0.0f, /* slopeScaledDepthBiasClamp */
|
0, /* depthClampEnable */
|
0, /* scissorEnable */
|
0, /* multisampleEnable */
|
0, /* aalineEnable */
|
1.0f, /* lineWidth */
|
0, /* lineStippleEnable */
|
0, /* lineStippleFactor */
|
0, /* lineStipplePattern */
|
0); /* provokingVertexLast */
|
|
|
assert(ret == PIPE_OK);
|
|
ret = SVGA3D_vgpu10_SetRasterizerState(svga->swc, id);
|
return ret;
|
}
|
else {
|
SVGA3dRenderState *rs;
|
unsigned count = 0;
|
const unsigned COUNT = 2;
|
enum pipe_error ret;
|
|
ret = SVGA3D_BeginSetRenderState( svga->swc, &rs, COUNT );
|
if (ret != PIPE_OK)
|
return ret;
|
|
/* Always use D3D style coordinate space as this is the only one
|
* which is implemented on all backends.
|
*/
|
EMIT_RS(rs, count, SVGA3D_RS_COORDINATETYPE,
|
SVGA3D_COORDINATE_LEFTHANDED );
|
EMIT_RS(rs, count, SVGA3D_RS_FRONTWINDING, SVGA3D_FRONTWINDING_CW );
|
|
assert( COUNT == count );
|
SVGA_FIFOCommitAll( svga->swc );
|
|
return PIPE_OK;
|
}
|
}
|