- Install custom (though inactive) pipeline - Track depth test and culling state in hardware registerstags/unichrome-last-xinerama
@@ -30,6 +30,7 @@ DRIVER_SOURCES = \ | |||
r300_ioctl.c \ | |||
r300_cmdbuf.c \ | |||
r300_state.c \ | |||
r300_render.c \ | |||
\ | |||
r200_context.c \ | |||
r200_ioctl.c \ |
@@ -50,6 +50,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "r300_cmdbuf.h" | |||
// Set this to 1 for extremely verbose debugging of command buffers | |||
#define DEBUG_CMDBUF 0 | |||
/** | |||
* Send the current command buffer via ioctl to the hardware. | |||
*/ | |||
@@ -69,7 +73,7 @@ int r300FlushCmdBuf(r300ContextPtr r300, const char* caller) | |||
fprintf(stderr, "%s from %s - %i cliprects\n", | |||
__FUNCTION__, caller, r300->radeon.numClipRects); | |||
if (RADEON_DEBUG & DEBUG_VERBOSE) | |||
if (DEBUG_CMDBUF && RADEON_DEBUG & DEBUG_VERBOSE) | |||
for (i = start; i < r300->cmdbuf.count_used; ++i) | |||
fprintf(stderr, "%d: %08x\n", i, | |||
r300->cmdbuf.cmd_buf[i]); | |||
@@ -140,7 +144,7 @@ static __inline__ void r300DoEmitState(r300ContextPtr r300, GLboolean dirty) | |||
dest = r300->cmdbuf.cmd_buf + r300->cmdbuf.count_used; | |||
if (RADEON_DEBUG & DEBUG_STATE) { | |||
if (DEBUG_CMDBUF && RADEON_DEBUG & DEBUG_STATE) { | |||
foreach(atom, &r300->hw.atomlist) { | |||
if ((atom->dirty || r300->hw.all_dirty) == dirty) { | |||
int dwords = (*atom->check)(r300, atom); | |||
@@ -324,8 +328,10 @@ void r300InitCmdBuf(r300ContextPtr r300) | |||
r300->hw.unk4288.cmd[0] = cmducs(0x4288, 5); | |||
ALLOC_STATE( unk42A0, always, 2, "unk42A0", 0 ); | |||
r300->hw.unk42A0.cmd[0] = cmducs(0x42A0, 1); | |||
ALLOC_STATE( unk42B4, always, 3, "unk42B4", 0 ); | |||
r300->hw.unk42B4.cmd[0] = cmducs(0x42B4, 2); | |||
ALLOC_STATE( unk42B4, always, 2, "unk42B4", 0 ); | |||
r300->hw.unk42B4.cmd[0] = cmducs(0x42B4, 1); | |||
ALLOC_STATE( cul, always, R300_CUL_CMDSIZE, "cul", 0 ); | |||
r300->hw.cul.cmd[R300_CUL_CMD_0] = cmducs(R300_RE_CULL_CNTL, 1); | |||
ALLOC_STATE( unk42C0, always, 3, "unk42C0", 0 ); | |||
r300->hw.unk42C0.cmd[0] = cmducs(0x42C0, 2); | |||
ALLOC_STATE( rc, always, R300_RC_CMDSIZE, "rc", 0 ); | |||
@@ -428,6 +434,7 @@ void r300InitCmdBuf(r300ContextPtr r300) | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.unk4288); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.unk42A0); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.unk42B4); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.cul); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.unk42C0); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.rc); | |||
insert_at_tail(&r300->hw.atomlist, &r300->hw.ri); |
@@ -100,15 +100,13 @@ static const char *const card_extensions[] = { | |||
NULL | |||
}; | |||
#if 0 | |||
extern const struct tnl_pipeline_stage _r300_render_stage; | |||
extern const struct tnl_pipeline_stage _r300_tcl_stage; | |||
extern struct tnl_pipeline_stage _r300_render_stage; | |||
static const struct tnl_pipeline_stage *r300_pipeline[] = { | |||
/* Try and go straight to t&l | |||
*/ | |||
&_r300_tcl_stage, | |||
// &_r300_tcl_stage, | |||
/* Catch any t&l fallbacks | |||
*/ | |||
@@ -136,7 +134,7 @@ static const struct tnl_pipeline_stage *r300_pipeline[] = { | |||
&_tnl_render_stage, /* FALLBACK */ | |||
0, | |||
}; | |||
#endif | |||
/* Create the device specific rendering context. | |||
*/ | |||
@@ -217,13 +215,10 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual, | |||
_swsetup_CreateContext(ctx); | |||
_ae_create_context(ctx); | |||
#if 0 | |||
/* Install the customized pipeline: | |||
*/ | |||
_tnl_destroy_pipeline(ctx); | |||
_tnl_install_pipeline(ctx, r200_pipeline); | |||
ctx->Driver.FlushVertices = r200FlushVertices; | |||
#endif | |||
_tnl_install_pipeline(ctx, r300_pipeline); | |||
/* Try and keep materials and vertices separate: | |||
*/ | |||
@@ -245,7 +240,6 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual, | |||
/* plug in a few more device driver functions */ | |||
/* XXX these should really go right after _mesa_init_driver_functions() */ | |||
r200InitPixelFuncs(ctx); | |||
r200InitTnlFuncs(ctx); | |||
r200InitSwtcl(ctx); | |||
#endif | |||
TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; |
@@ -126,6 +126,10 @@ struct r300_state_atom { | |||
#define R300_PS_POINTSIZE 1 | |||
#define R300_PS_CMDSIZE 2 | |||
#define R300_CUL_CMD_0 0 | |||
#define R300_CUL_CULL 1 | |||
#define R300_CUL_CMDSIZE 2 | |||
#define R300_RC_CMD_0 0 | |||
#define R300_RC_CNTL_0 1 | |||
#define R300_RC_CNTL_1 2 | |||
@@ -247,6 +251,7 @@ struct r300_hw_state { | |||
struct r300_state_atom unk4288; /* (4288) */ | |||
struct r300_state_atom unk42A0; /* (42A0) */ | |||
struct r300_state_atom unk42B4; /* (42B4) */ | |||
struct r300_state_atom cul; /* cull cntl (42B8) */ | |||
struct r300_state_atom unk42C0; /* (42C0) */ | |||
struct r300_state_atom rc; /* rs control (4300) */ | |||
struct r300_state_atom ri; /* rs interpolators (4310) */ |
@@ -171,7 +171,7 @@ static void r300ClearBuffer(r300ContextPtr r300, int flags, int buffer) | |||
R300_STATECHANGE(r300, zc); | |||
if (flags & CLEARBUFFER_DEPTH) { | |||
r300->hw.zc.cmd[R300_ZC_CNTL_0] = 0x6; // test and write | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_RB3D_Z_TEST_ALWAYS; | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_ALWAYS; | |||
/* | |||
R300_STATECHANGE(r300, zb); | |||
r300->hw.zb.cmd[R300_ZB_OFFSET] = |
@@ -0,0 +1,189 @@ | |||
/************************************************************************** | |||
Copyright (C) 2004 Nicolai Haehnle. | |||
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 | |||
on the rights to use, copy, modify, merge, publish, distribute, sub | |||
license, 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 (including the next | |||
paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL | |||
ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS 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. | |||
**************************************************************************/ | |||
/* | |||
* Authors: | |||
* Nicolai Haehnle <prefect_@gmx.net> | |||
*/ | |||
#include "glheader.h" | |||
#include "state.h" | |||
#include "imports.h" | |||
#include "enums.h" | |||
#include "macros.h" | |||
#include "context.h" | |||
#include "dd.h" | |||
#include "simple_list.h" | |||
#include "api_arrayelt.h" | |||
#include "swrast/swrast.h" | |||
#include "swrast_setup/swrast_setup.h" | |||
#include "array_cache/acache.h" | |||
#include "tnl/tnl.h" | |||
#include "radeon_ioctl.h" | |||
#include "radeon_state.h" | |||
#include "r300_context.h" | |||
#include "r300_ioctl.h" | |||
#include "r300_state.h" | |||
#include "r300_reg.h" | |||
#include "r300_program.h" | |||
/********************************************************************** | |||
* Hardware rasterization | |||
* | |||
* When we fell back to software TCL, we still try to use the | |||
* rasterization hardware for rendering. | |||
**********************************************************************/ | |||
/** | |||
* Called by the pipeline manager to render a batch of primitives. | |||
* We can return true to pass on to the next stage (i.e. software | |||
* rasterization) or false to indicate that the pipeline has finished | |||
* after we render something. | |||
*/ | |||
static GLboolean r300_run_render(GLcontext *ctx, | |||
struct tnl_pipeline_stage *stage) | |||
{ | |||
if (RADEON_DEBUG == DEBUG_PRIMS) | |||
fprintf(stderr, "%s\n", __FUNCTION__); | |||
return GL_TRUE; | |||
#if 0 | |||
mgaContextPtr mmesa = MGA_CONTEXT(ctx); | |||
TNLcontext *tnl = TNL_CONTEXT(ctx); | |||
struct vertex_buffer *VB = &tnl->vb; | |||
GLuint i; | |||
/* Don't handle clipping or indexed vertices or vertex manipulations. | |||
*/ | |||
if (mmesa->RenderIndex != 0 || | |||
!mga_validate_render( ctx, VB )) { | |||
return GL_TRUE; | |||
} | |||
tnl->Driver.Render.Start( ctx ); | |||
mmesa->SetupNewInputs = ~0; | |||
for (i = 0 ; i < VB->PrimitiveCount ; i++) | |||
{ | |||
GLuint prim = VB->Primitive[i].mode; | |||
GLuint start = VB->Primitive[i].start; | |||
GLuint length = VB->Primitive[i].count; | |||
if (!length) | |||
continue; | |||
mga_render_tab_verts[prim & PRIM_MODE_MASK]( ctx, start, start + length, | |||
prim); | |||
} | |||
tnl->Driver.Render.Finish( ctx ); | |||
return GL_FALSE; /* finished the pipe */ | |||
#endif | |||
} | |||
/** | |||
* Called by the pipeline manager once before rendering. | |||
* We check the GL state here to | |||
* a) decide whether we can do the current state in hardware and | |||
* b) update hardware registers | |||
*/ | |||
#define FALLBACK_IF(expr) \ | |||
do { \ | |||
if (expr) { \ | |||
if (RADEON_DEBUG & DEBUG_FALLBACKS) \ | |||
fprintf(stderr, "%s: fallback:%s\n", \ | |||
__FUNCTION__, #expr); \ | |||
stage->active = GL_FALSE; \ | |||
return; \ | |||
} \ | |||
} while(0) | |||
static void r300_check_render(GLcontext *ctx, struct tnl_pipeline_stage *stage) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
int i; | |||
if (RADEON_DEBUG & DEBUG_STATE) | |||
fprintf(stderr, "%s\n", __FUNCTION__); | |||
/* We only support rendering in hardware for now */ | |||
if (ctx->RenderMode != GL_RENDER) { | |||
stage->active = GL_FALSE; | |||
return; | |||
} | |||
// I failed to figure out how dither works in hardware, | |||
// let's just ignore it for now | |||
//FALLBACK_IF(ctx->Color.DitherFlag); | |||
/* I'm almost certain I forgot something here */ | |||
FALLBACK_IF(ctx->Color.AlphaEnabled); // GL_ALPHA_TEST | |||
FALLBACK_IF(ctx->Color.BlendEnabled); // GL_BLEND | |||
FALLBACK_IF(ctx->Fog.Enabled); // GL_FOG | |||
FALLBACK_IF(ctx->Line.SmoothFlag); // GL_LINE_SMOOTH | |||
FALLBACK_IF(ctx->Line.StippleFlag); // GL_LINE_STIPPLE | |||
FALLBACK_IF(ctx->Point.SmoothFlag); // GL_POINT_SMOOTH | |||
if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) | |||
FALLBACK_IF(ctx->Point.PointSprite); // GL_POINT_SPRITE_NV | |||
FALLBACK_IF(ctx->Polygon.OffsetPoint); // GL_POLYGON_OFFSET_POINT | |||
FALLBACK_IF(ctx->Polygon.OffsetLine); // GL_POLYGON_OFFSET_LINE | |||
FALLBACK_IF(ctx->Polygon.OffsetFill); // GL_POLYGON_OFFSET_FILL | |||
FALLBACK_IF(ctx->Polygon.SmoothFlag); // GL_POLYGON_SMOOTH | |||
FALLBACK_IF(ctx->Polygon.StippleFlag); // GL_POLYGON_STIPPLE | |||
FALLBACK_IF(ctx->Stencil.Enabled); // GL_STENCIL_TEST | |||
FALLBACK_IF(ctx->Multisample.Enabled); // GL_MULTISAMPLE_ARB | |||
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) | |||
FALLBACK_IF(ctx->Texture.Unit[i].Enabled); | |||
stage->active = GL_FALSE; | |||
} | |||
static void dtr(struct tnl_pipeline_stage *stage) | |||
{ | |||
(void)stage; | |||
} | |||
const struct tnl_pipeline_stage _r300_render_stage = { | |||
"r300 hw rasterize", | |||
_NEW_ALL, /* re-check (always re-check for now) */ | |||
0, /* re-run (always runs) */ | |||
GL_TRUE, /* active */ | |||
0, 0, /* inputs (set in check_render), outputs */ | |||
0, 0, /* changed_inputs, private */ | |||
dtr, /* destructor */ | |||
r300_check_render, /* check */ | |||
r300_run_render /* run */ | |||
}; |
@@ -58,17 +58,67 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
#include "r300_program.h" | |||
/** | |||
* Update our tracked culling state based on Mesa's state. | |||
*/ | |||
static void r300UpdateCulling(GLcontext* ctx) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
uint32_t val = 0; | |||
R300_STATECHANGE(r300, cul); | |||
if (ctx->Polygon.CullFlag) { | |||
if (ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) | |||
val = R300_CULL_FRONT|R300_CULL_BACK; | |||
else if (ctx->Polygon.CullFaceMode == GL_FRONT) | |||
val = R300_CULL_FRONT; | |||
else | |||
val = R300_CULL_BACK; | |||
if (ctx->Polygon.FrontFace == GL_CW) | |||
val |= R300_FRONT_FACE_CW; | |||
else | |||
val |= R300_FRONT_FACE_CCW; | |||
} | |||
r300->hw.cul.cmd[R300_CUL_CULL] = val; | |||
} | |||
/** | |||
* Handle glEnable()/glDisable(). | |||
* | |||
* \note Mesa already filters redundant calls to glEnable/glDisable. | |||
*/ | |||
static void r300Enable(GLcontext* ctx, GLenum cap, GLboolean state) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
uint32_t newval; | |||
if (RADEON_DEBUG & DEBUG_STATE) | |||
fprintf(stderr, "%s( %s = %s )\n", __FUNCTION__, | |||
_mesa_lookup_enum_by_nr(cap), | |||
state ? "GL_TRUE" : "GL_FALSE"); | |||
switch (cap) { | |||
case GL_DEPTH_TEST: | |||
R300_STATECHANGE(r300, zc); | |||
if (state) { | |||
if (ctx->Depth.Mask) | |||
newval = R300_RB3D_Z_TEST_AND_WRITE; | |||
else | |||
newval = R300_RB3D_Z_TEST; | |||
} else | |||
newval = 0; | |||
r300->hw.zc.cmd[R300_ZC_CNTL_0] = newval; | |||
break; | |||
case GL_CULL_FACE: | |||
r300UpdateCulling(ctx); | |||
break; | |||
default: | |||
radeonEnable(ctx, cap, state); | |||
return; | |||
@@ -76,6 +126,90 @@ static void r300Enable(GLcontext* ctx, GLenum cap, GLboolean state) | |||
} | |||
/** | |||
* Change the culling mode. | |||
* | |||
* \note Mesa already filters redundant calls to this function. | |||
*/ | |||
static void r300CullFace(GLcontext* ctx, GLenum mode) | |||
{ | |||
(void)mode; | |||
r300UpdateCulling(ctx); | |||
} | |||
/** | |||
* Change the polygon orientation. | |||
* | |||
* \note Mesa already filters redundant calls to this function. | |||
*/ | |||
static void r300FrontFace(GLcontext* ctx, GLenum mode) | |||
{ | |||
(void)mode; | |||
r300UpdateCulling(ctx); | |||
} | |||
/** | |||
* Change the depth testing function. | |||
* | |||
* \note Mesa already filters redundant calls to this function. | |||
*/ | |||
static void r300DepthFunc(GLcontext* ctx, GLenum func) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
R300_STATECHANGE(r300, zc); | |||
switch(func) { | |||
case GL_NEVER: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_NEVER; | |||
break; | |||
case GL_LESS: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_LESS; | |||
break; | |||
case GL_EQUAL: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_EQUAL; | |||
break; | |||
case GL_LEQUAL: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_LEQUAL; | |||
break; | |||
case GL_GREATER: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_GREATER; | |||
break; | |||
case GL_NOTEQUAL: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_NEQUAL; | |||
break; | |||
case GL_GEQUAL: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_GEQUAL; | |||
break; | |||
case GL_ALWAYS: | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_ALWAYS; | |||
break; | |||
} | |||
} | |||
/** | |||
* Enable/Disable depth writing. | |||
* | |||
* \note Mesa already filters redundant calls to this function. | |||
*/ | |||
static void r300DepthMask(GLcontext* ctx, GLboolean mask) | |||
{ | |||
r300ContextPtr r300 = R300_CONTEXT(ctx); | |||
if (!ctx->Depth.Test) | |||
return; | |||
R300_STATECHANGE(r300, zc); | |||
r300->hw.zc.cmd[R300_ZC_CNTL_0] = mask | |||
? R300_RB3D_Z_TEST_AND_WRITE : R300_RB3D_Z_TEST; | |||
} | |||
/** | |||
* Handle glColorMask() | |||
*/ | |||
@@ -141,11 +275,17 @@ void r300ResetHwState(r300ContextPtr r300) | |||
r300PackFloat32(v[MAT_TZ]); | |||
} | |||
r300->hw.cmk.cmd[R300_CMK_COLORMASK] = | |||
(ctx->Color.ColorMask[BCOMP] ? R300_COLORMASK0_B : 0) | | |||
(ctx->Color.ColorMask[GCOMP] ? R300_COLORMASK0_G : 0) | | |||
(ctx->Color.ColorMask[RCOMP] ? R300_COLORMASK0_R : 0) | | |||
(ctx->Color.ColorMask[ACOMP] ? R300_COLORMASK0_A : 0); | |||
r300ColorMask(ctx, | |||
ctx->Color.ColorMask[RCOMP], | |||
ctx->Color.ColorMask[GCOMP], | |||
ctx->Color.ColorMask[BCOMP], | |||
ctx->Color.ColorMask[ACOMP]); | |||
r300Enable(ctx, GL_DEPTH_TEST, ctx->Depth.Test); | |||
r300DepthMask(ctx, ctx->Depth.Mask); | |||
r300DepthFunc(ctx, ctx->Depth.Func); | |||
r300UpdateCulling(ctx); | |||
//BEGIN: TODO | |||
r300->hw.unk2080.cmd[1] = 0x0030045A; | |||
@@ -233,7 +373,6 @@ void r300ResetHwState(r300ContextPtr r300) | |||
r300->hw.unk42A0.cmd[1] = 0x00000000; | |||
r300->hw.unk42B4.cmd[1] = 0x00000000; | |||
r300->hw.unk42B4.cmd[2] = 0x00000000; | |||
r300->hw.unk42C0.cmd[1] = 0x4B7FFFFF; | |||
r300->hw.unk42C0.cmd[2] = 0x00000000; | |||
@@ -312,9 +451,6 @@ void r300ResetHwState(r300ContextPtr r300) | |||
r300->hw.unk4E88.cmd[1] = 0; | |||
r300->hw.zc.cmd[R300_ZC_CNTL_0] = 0; | |||
r300->hw.zc.cmd[R300_ZC_CNTL_1] = 0; | |||
r300->hw.unk4F08.cmd[1] = 0x00FFFF00; | |||
r300->hw.unk4F10.cmd[1] = 0x00000002; // depthbuffer format? | |||
@@ -383,5 +519,9 @@ void r300InitStateFuncs(struct dd_function_table* functions) | |||
functions->UpdateState = r300InvalidateState; | |||
functions->Enable = r300Enable; | |||
functions->ColorMask = r300ColorMask; | |||
functions->DepthFunc = r300DepthFunc; | |||
functions->DepthMask = r300DepthMask; | |||
functions->CullFace = r300CullFace; | |||
functions->FrontFace = r300FrontFace; | |||
} | |||