blob: 1d413d3473440f4edbb9ff6a88c1b3b6fdca788c [file] [log] [blame]
/*
* Copyright 2000-2001 VA Linux Systems, 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
* 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
* VA LINUX SYSTEMS AND/OR ITS 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:
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include "mtypes.h"
#include "colormac.h"
#include "dd.h"
#include "mm.h"
#include "mgacontext.h"
#include "mgadd.h"
#include "mgastate.h"
#include "mgatex.h"
#include "mgavb.h"
#include "mgatris.h"
#include "mgaioctl.h"
#include "mgaregs.h"
#include "swrast/swrast.h"
#include "vbo/vbo.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_pipeline.h"
#include "swrast_setup/swrast_setup.h"
#include "xmlpool.h"
#include "drirenderbuffer.h"
static void updateSpecularLighting( GLcontext *ctx );
static const GLuint mgarop_NoBLK[16] = {
DC_atype_rpl | 0x00000000, DC_atype_rstr | 0x00080000,
DC_atype_rstr | 0x00040000, DC_atype_rpl | 0x000c0000,
DC_atype_rstr | 0x00020000, DC_atype_rstr | 0x000a0000,
DC_atype_rstr | 0x00060000, DC_atype_rstr | 0x000e0000,
DC_atype_rstr | 0x00010000, DC_atype_rstr | 0x00090000,
DC_atype_rstr | 0x00050000, DC_atype_rstr | 0x000d0000,
DC_atype_rpl | 0x00030000, DC_atype_rstr | 0x000b0000,
DC_atype_rstr | 0x00070000, DC_atype_rpl | 0x000f0000
};
/* =============================================================
* Alpha blending
*/
static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLubyte refByte;
GLuint a;
CLAMPED_FLOAT_TO_UBYTE(refByte, ref);
switch ( func ) {
case GL_NEVER:
a = AC_atmode_alt;
refByte = 0;
break;
case GL_LESS:
a = AC_atmode_alt;
break;
case GL_GEQUAL:
a = AC_atmode_agte;
break;
case GL_LEQUAL:
a = AC_atmode_alte;
break;
case GL_GREATER:
a = AC_atmode_agt;
break;
case GL_NOTEQUAL:
a = AC_atmode_ane;
break;
case GL_EQUAL:
a = AC_atmode_ae;
break;
case GL_ALWAYS:
a = AC_atmode_noacmp;
break;
default:
a = 0;
break;
}
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.alpha_func = a | MGA_FIELD( AC_atref, refByte );
}
static void updateBlendLogicOp(GLcontext *ctx)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLboolean logicOp = RGBA_LOGICOP_ENABLED(ctx);
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.blend_func_enable =
(ctx->Color.BlendEnabled && !logicOp) ? ~0 : 0;
FALLBACK( ctx, MGA_FALLBACK_BLEND,
ctx->Color.BlendEnabled && !logicOp &&
mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) );
}
static void mgaDDBlendEquationSeparate(GLcontext *ctx,
GLenum modeRGB, GLenum modeA)
{
assert( modeRGB == modeA );
updateBlendLogicOp( ctx );
}
static void mgaDDBlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB,
GLenum dfactorRGB, GLenum sfactorA,
GLenum dfactorA )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLuint src;
GLuint dst;
switch (ctx->Color.BlendSrcRGB) {
case GL_ZERO:
src = AC_src_zero; break;
case GL_SRC_ALPHA:
src = AC_src_src_alpha; break;
case GL_ONE:
default: /* never happens */
src = AC_src_one; break;
case GL_DST_COLOR:
src = AC_src_dst_color; break;
case GL_ONE_MINUS_DST_COLOR:
src = AC_src_om_dst_color; break;
case GL_ONE_MINUS_SRC_ALPHA:
src = AC_src_om_src_alpha; break;
case GL_DST_ALPHA:
src = (ctx->Visual.alphaBits > 0)
? AC_src_dst_alpha : AC_src_one;
break;
case GL_ONE_MINUS_DST_ALPHA:
src = (ctx->Visual.alphaBits > 0)
? AC_src_om_dst_alpha : AC_src_zero;
break;
case GL_SRC_ALPHA_SATURATE:
src = (ctx->Visual.alphaBits > 0)
? AC_src_src_alpha_sat : AC_src_zero;
break;
}
switch (ctx->Color.BlendDstRGB) {
case GL_SRC_ALPHA:
dst = AC_dst_src_alpha; break;
case GL_ONE_MINUS_SRC_ALPHA:
dst = AC_dst_om_src_alpha; break;
default: /* never happens */
case GL_ZERO:
dst = AC_dst_zero; break;
case GL_ONE:
dst = AC_dst_one; break;
case GL_SRC_COLOR:
dst = AC_dst_src_color; break;
case GL_ONE_MINUS_SRC_COLOR:
dst = AC_dst_om_src_color; break;
case GL_DST_ALPHA:
dst = (ctx->Visual.alphaBits > 0)
? AC_dst_dst_alpha : AC_dst_one;
break;
case GL_ONE_MINUS_DST_ALPHA:
dst = (ctx->Visual.alphaBits > 0)
? AC_dst_om_dst_alpha : AC_dst_zero;
break;
}
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.blend_func = (src | dst);
FALLBACK( ctx, MGA_FALLBACK_BLEND,
ctx->Color.BlendEnabled && !RGBA_LOGICOP_ENABLED(ctx) &&
mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) );
}
/* =============================================================
* Depth testing
*/
static void mgaDDDepthFunc(GLcontext *ctx, GLenum func)
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
int zmode;
switch (func) {
case GL_NEVER:
/* can't do this in h/w, we'll use a s/w fallback */
FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Test);
/* FALLTHROUGH */
case GL_ALWAYS:
zmode = DC_zmode_nozcmp; break;
case GL_LESS:
zmode = DC_zmode_zlt; break;
case GL_LEQUAL:
zmode = DC_zmode_zlte; break;
case GL_EQUAL:
zmode = DC_zmode_ze; break;
case GL_GREATER:
zmode = DC_zmode_zgt; break;
case GL_GEQUAL:
zmode = DC_zmode_zgte; break;
case GL_NOTEQUAL:
zmode = DC_zmode_zne; break;
default:
zmode = 0; break;
}
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.zmode &= DC_zmode_MASK;
mmesa->hw.zmode |= zmode;
}
static void mgaDDDepthMask(GLcontext *ctx, GLboolean flag)
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.zmode &= DC_atype_MASK;
mmesa->hw.zmode |= (flag) ? DC_atype_zi : DC_atype_i;
}
static void mgaDDClearDepth(GLcontext *ctx, GLclampd d)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
/* Select the Z depth. The ~ is used because the _MASK values in the
* MGA driver are used to mask OFF the selected bits. In this case,
* we want to mask off everything except the MA_zwidth bits.
*/
switch (mmesa->setup.maccess & ~MA_zwidth_MASK) {
case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break;
case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break;
case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break;
default: return;
}
}
/* =============================================================
* Fog
*/
static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
if (pname == GL_FOG_COLOR) {
GLuint color = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F),
(GLubyte)(ctx->Fog.Color[1]*255.0F),
(GLubyte)(ctx->Fog.Color[2]*255.0F));
MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT);
mmesa->setup.fogcolor = color;
}
}
/* =============================================================
* Scissoring
*/
void mgaUpdateClipping(const GLcontext *ctx)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
if (mmesa->driDrawable)
{
int x1 = mmesa->driDrawable->x + ctx->Scissor.X;
int y1 = mmesa->driDrawable->y + mmesa->driDrawable->h
- (ctx->Scissor.Y + ctx->Scissor.Height);
int x2 = x1 + ctx->Scissor.Width;
int y2 = y1 + ctx->Scissor.Height;
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 < 0) x2 = 0;
if (y2 < 0) y2 = 0;
mmesa->scissor_rect.x1 = x1;
mmesa->scissor_rect.y1 = y1;
mmesa->scissor_rect.x2 = x2;
mmesa->scissor_rect.y2 = y2;
mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
}
}
static void mgaDDScissor( GLcontext *ctx, GLint x, GLint y,
GLsizei w, GLsizei h )
{
if ( ctx->Scissor.Enabled ) {
FLUSH_BATCH( MGA_CONTEXT(ctx) ); /* don't pipeline cliprect changes */
mgaUpdateClipping( ctx );
}
}
/* =============================================================
* Culling
*/
#define _CULL_DISABLE 0
#define _CULL_NEGATIVE ((1<<11)|(1<<5)|(1<<16))
#define _CULL_POSITIVE (1<<11)
static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum unused)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
if (ctx->Polygon.CullFlag &&
ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK)
{
mmesa->hw.cull = _CULL_NEGATIVE;
if (ctx->Polygon.CullFaceMode == GL_FRONT)
mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
if (ctx->Polygon.FrontFace != GL_CCW)
mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
mmesa->hw.cull_dualtex = mmesa->hw.cull ^
(_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */
}
else {
mmesa->hw.cull = _CULL_DISABLE;
mmesa->hw.cull_dualtex = _CULL_DISABLE;
}
}
/* =============================================================
* Masks
*/
static void mgaDDColorMask(GLcontext *ctx,
GLboolean r, GLboolean g,
GLboolean b, GLboolean a )
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
GLuint mask = mgaPackColor(mgaScreen->cpp,
ctx->Color.ColorMask[RCOMP],
ctx->Color.ColorMask[GCOMP],
ctx->Color.ColorMask[BCOMP],
ctx->Color.ColorMask[ACOMP]);
if (mgaScreen->cpp == 2)
mask = mask | (mask << 16);
if (mmesa->setup.plnwt != mask) {
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->setup.plnwt = mask;
}
}
/* =============================================================
* Polygon state
*/
static int mgaStipples[16] = {
0xffff,
0xa5a5,
0x5a5a,
0xa0a0,
0x5050,
0x0a0a,
0x0505,
0x8020,
0x0401,
0x1040,
0x0208,
0x0802,
0x4010,
0x0104,
0x2080,
0x0000
};
/**
* The MGA supports a subset of possible 4x4 stipples natively, GL
* wants 32x32. Fortunately stipple is usually a repeating pattern.
*
* \param ctx GL rendering context to be affected
* \param mask Pointer to the 32x32 stipple mask
*/
static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
const GLubyte *m = mask;
GLubyte p[4];
int i,j,k;
int active = (ctx->Polygon.StippleFlag &&
mmesa->raster_primitive == GL_TRIANGLES);
GLuint stipple;
FLUSH_BATCH(mmesa);
mmesa->haveHwStipple = 0;
if (active) {
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
mmesa->setup.dwgctl &= ~(0xf<<20);
}
p[0] = mask[0] & 0xf; p[0] |= p[0] << 4;
p[1] = mask[4] & 0xf; p[1] |= p[1] << 4;
p[2] = mask[8] & 0xf; p[2] |= p[2] << 4;
p[3] = mask[12] & 0xf; p[3] |= p[3] << 4;
for (k = 0 ; k < 8 ; k++)
for (j = 0 ; j < 4; j++)
for (i = 0 ; i < 4 ; i++)
if (*m++ != p[j]) {
return;
}
stipple = ( ((p[0] & 0xf) << 0) |
((p[1] & 0xf) << 4) |
((p[2] & 0xf) << 8) |
((p[3] & 0xf) << 12) );
for (i = 0 ; i < 16 ; i++)
if (mgaStipples[i] == stipple) {
mmesa->poly_stipple = i<<20;
mmesa->haveHwStipple = 1;
break;
}
if (active) {
mmesa->setup.dwgctl &= ~(0xf<<20);
mmesa->setup.dwgctl |= mmesa->poly_stipple;
}
}
/* =============================================================
* Rendering attributes
*
* We really don't want to recalculate all this every time we bind a
* texture. These things shouldn't change all that often, so it makes
* sense to break them out of the core texture state update routines.
*/
static void updateSpecularLighting( GLcontext *ctx )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
unsigned int specen;
specen = NEED_SECONDARY_COLOR(ctx) ? TMC_specen_enable : 0;
if ( specen != mmesa->hw.specen ) {
mmesa->hw.specen = specen;
mmesa->dirty |= MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1;
}
}
/* =============================================================
* Materials
*/
static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname,
const GLfloat *param)
{
if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) {
FLUSH_BATCH( MGA_CONTEXT(ctx) );
updateSpecularLighting( ctx );
}
}
/* =============================================================
* Stencil
*/
static void
mgaDDStencilFuncSeparate(GLcontext *ctx, GLenum face, GLenum func, GLint ref,
GLuint mask)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLuint stencil;
GLuint stencilctl;
stencil = MGA_FIELD( S_sref, ref ) | MGA_FIELD( S_smsk, mask );
switch (func)
{
case GL_NEVER:
stencilctl = SC_smode_snever;
break;
case GL_LESS:
stencilctl = SC_smode_slt;
break;
case GL_LEQUAL:
stencilctl = SC_smode_slte;
break;
case GL_GREATER:
stencilctl = SC_smode_sgt;
break;
case GL_GEQUAL:
stencilctl = SC_smode_sgte;
break;
case GL_NOTEQUAL:
stencilctl = SC_smode_sne;
break;
case GL_EQUAL:
stencilctl = SC_smode_se;
break;
case GL_ALWAYS:
default:
stencilctl = SC_smode_salways;
break;
}
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.stencil &= (S_sref_MASK & S_smsk_MASK);
mmesa->hw.stencil |= stencil;
mmesa->hw.stencilctl &= SC_smode_MASK;
mmesa->hw.stencilctl |= stencilctl;
}
static void
mgaDDStencilMaskSeparate(GLcontext *ctx, GLenum face, GLuint mask)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.stencil &= S_swtmsk_MASK;
mmesa->hw.stencil |= MGA_FIELD( S_swtmsk, mask );
}
static void
mgaDDStencilOpSeparate(GLcontext *ctx, GLenum face, GLenum fail, GLenum zfail,
GLenum zpass)
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLuint stencilctl;
stencilctl = 0;
switch (ctx->Stencil.FailFunc[0])
{
case GL_KEEP:
stencilctl |= SC_sfailop_keep;
break;
case GL_ZERO:
stencilctl |= SC_sfailop_zero;
break;
case GL_REPLACE:
stencilctl |= SC_sfailop_replace;
break;
case GL_INCR:
stencilctl |= SC_sfailop_incrsat;
break;
case GL_DECR:
stencilctl |= SC_sfailop_decrsat;
break;
case GL_INCR_WRAP:
stencilctl |= SC_sfailop_incr;
break;
case GL_DECR_WRAP:
stencilctl |= SC_sfailop_decr;
break;
case GL_INVERT:
stencilctl |= SC_sfailop_invert;
break;
default:
break;
}
switch (ctx->Stencil.ZFailFunc[0])
{
case GL_KEEP:
stencilctl |= SC_szfailop_keep;
break;
case GL_ZERO:
stencilctl |= SC_szfailop_zero;
break;
case GL_REPLACE:
stencilctl |= SC_szfailop_replace;
break;
case GL_INCR:
stencilctl |= SC_szfailop_incrsat;
break;
case GL_DECR:
stencilctl |= SC_szfailop_decrsat;
break;
case GL_INCR_WRAP:
stencilctl |= SC_szfailop_incr;
break;
case GL_DECR_WRAP:
stencilctl |= SC_szfailop_decr;
break;
case GL_INVERT:
stencilctl |= SC_szfailop_invert;
break;
default:
break;
}
switch (ctx->Stencil.ZPassFunc[0])
{
case GL_KEEP:
stencilctl |= SC_szpassop_keep;
break;
case GL_ZERO:
stencilctl |= SC_szpassop_zero;
break;
case GL_REPLACE:
stencilctl |= SC_szpassop_replace;
break;
case GL_INCR:
stencilctl |= SC_szpassop_incrsat;
break;
case GL_DECR:
stencilctl |= SC_szpassop_decrsat;
break;
case GL_INCR_WRAP:
stencilctl |= SC_szpassop_incr;
break;
case GL_DECR_WRAP:
stencilctl |= SC_szpassop_decr;
break;
case GL_INVERT:
stencilctl |= SC_szpassop_invert;
break;
default:
break;
}
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.stencilctl &= (SC_sfailop_MASK & SC_szfailop_MASK
& SC_szpassop_MASK);
mmesa->hw.stencilctl |= stencilctl;
}
/* =============================================================
* Window position and viewport transformation
*/
void mgaCalcViewport( GLcontext *ctx )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
const GLfloat *v = ctx->Viewport._WindowMap.m;
GLfloat *m = mmesa->hw_viewport;
/* See also mga_translate_vertex.
*/
m[MAT_SX] = v[MAT_SX];
m[MAT_TX] = v[MAT_TX] + mmesa->drawX + SUBPIXEL_X;
m[MAT_SY] = - v[MAT_SY];
m[MAT_TY] = - v[MAT_TY] + mmesa->driDrawable->h + mmesa->drawY + SUBPIXEL_Y;
m[MAT_SZ] = v[MAT_SZ] * mmesa->depth_scale;
m[MAT_TZ] = v[MAT_TZ] * mmesa->depth_scale;
mmesa->SetupNewInputs = ~0;
}
static void mgaViewport( GLcontext *ctx,
GLint x, GLint y,
GLsizei width, GLsizei height )
{
mgaCalcViewport( ctx );
}
static void mgaDepthRange( GLcontext *ctx,
GLclampd nearval, GLclampd farval )
{
mgaCalcViewport( ctx );
}
/* =============================================================
* Miscellaneous
*/
static void mgaDDClearColor(GLcontext *ctx,
const GLfloat color[4] )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
GLubyte c[4];
CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp,
c[0], c[1], c[2], c[3]);
}
/* Fallback to swrast for select and feedback.
*/
static void mgaRenderMode( GLcontext *ctx, GLenum mode )
{
FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
}
static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.rop = mgarop_NoBLK[ opcode & 0x0f ];
}
static void mga_set_cliprects(mgaContextPtr mmesa)
{
__DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
if ((mmesa->draw_buffer != MGA_FRONT)
|| (driDrawable->numBackClipRects == 0)) {
if (driDrawable->numClipRects == 0) {
static drm_clip_rect_t zeroareacliprect = {0,0,0,0};
mmesa->numClipRects = 1;
mmesa->pClipRects = &zeroareacliprect;
} else {
mmesa->numClipRects = driDrawable->numClipRects;
mmesa->pClipRects = driDrawable->pClipRects;
}
mmesa->drawX = driDrawable->x;
mmesa->drawY = driDrawable->y;
} else {
mmesa->numClipRects = driDrawable->numBackClipRects;
mmesa->pClipRects = driDrawable->pBackClipRects;
mmesa->drawX = driDrawable->backX;
mmesa->drawY = driDrawable->backY;
}
mmesa->setup.dstorg = mmesa->drawOffset;
mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
}
void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers )
{
__DRIdrawablePrivate *const driDrawable = mmesa->driDrawable;
__DRIdrawablePrivate *const driReadable = mmesa->driReadable;
mmesa->dirty_cliprects = 0;
driUpdateFramebufferSize(mmesa->glCtx, driDrawable);
if (driDrawable != driReadable) {
driUpdateFramebufferSize(mmesa->glCtx, driReadable);
}
mga_set_cliprects(mmesa);
mgaUpdateClipping( mmesa->glCtx );
mgaCalcViewport( mmesa->glCtx );
}
static void mgaDDDrawBuffer(GLcontext *ctx, GLenum mode )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
FLUSH_BATCH( mmesa );
if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) {
/* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */
FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE );
return;
}
switch ( ctx->DrawBuffer->_ColorDrawBufferIndexes[0] ) {
case BUFFER_FRONT_LEFT:
mmesa->setup.dstorg = mmesa->mgaScreen->frontOffset;
mmesa->draw_buffer = MGA_FRONT;
break;
case BUFFER_BACK_LEFT:
mmesa->setup.dstorg = mmesa->mgaScreen->backOffset;
mmesa->draw_buffer = MGA_BACK;
break;
default:
FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE );
return;
}
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
mga_set_cliprects(mmesa);
FALLBACK(ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE);
}
static void mgaDDReadBuffer(GLcontext *ctx, GLenum mode )
{
/* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
}
/* =============================================================
* State enable/disable
*/
static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
switch(cap) {
case GL_DITHER:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
if (!ctx->Color.DitherFlag)
mmesa->setup.maccess |= MA_nodither_enable;
else
mmesa->setup.maccess &= ~MA_nodither_enable;
break;
case GL_LIGHTING:
case GL_COLOR_SUM_EXT:
FLUSH_BATCH( mmesa );
updateSpecularLighting( ctx );
break;
case GL_ALPHA_TEST:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->hw.alpha_func_enable = (state) ? ~0 : 0;
break;
case GL_DEPTH_TEST:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
FALLBACK (ctx, MGA_FALLBACK_DEPTH,
ctx->Depth.Func == GL_NEVER && ctx->Depth.Test);
break;
case GL_SCISSOR_TEST:
FLUSH_BATCH( mmesa );
mmesa->scissor = state;
mgaUpdateClipping( ctx );
break;
case GL_FOG:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
if (ctx->Fog.Enabled)
mmesa->setup.maccess |= MA_fogen_enable;
else
mmesa->setup.maccess &= ~MA_fogen_enable;
break;
case GL_CULL_FACE:
mgaDDCullFaceFrontFace( ctx, 0 );
break;
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D:
break;
case GL_POLYGON_STIPPLE:
if (mmesa->haveHwStipple && mmesa->raster_primitive == GL_TRIANGLES) {
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
mmesa->setup.dwgctl &= ~(0xf<<20);
if (state)
mmesa->setup.dwgctl |= mmesa->poly_stipple;
}
break;
case GL_BLEND:
case GL_COLOR_LOGIC_OP:
updateBlendLogicOp( ctx );
break;
case GL_STENCIL_TEST:
MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
if (mmesa->hw_stencil) {
mmesa->hw.stencil_enable = ( state ) ? ~0 : 0;
}
else {
FALLBACK( ctx, MGA_FALLBACK_STENCIL, state );
}
default:
break;
}
}
/* =============================================================
*/
static void mgaDDPrintDirty( const char *msg, GLuint state )
{
fprintf(stderr, "%s (0x%03x): %s%s%s%s%s%s%s\n",
msg,
(unsigned int) state,
(state & MGA_WAIT_AGE) ? "wait-age " : "",
(state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img " : "",
(state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img " : "",
(state & MGA_UPLOAD_CONTEXT) ? "upload-ctx " : "",
(state & MGA_UPLOAD_TEX0) ? "upload-tex0 " : "",
(state & MGA_UPLOAD_TEX1) ? "upload-tex1 " : "",
(state & MGA_UPLOAD_PIPE) ? "upload-pipe " : ""
);
}
/* Push the state into the sarea and/or texture memory.
*/
void mgaEmitHwStateLocked( mgaContextPtr mmesa )
{
drm_mga_sarea_t *sarea = mmesa->sarea;
GLcontext * ctx = mmesa->glCtx;
if (MGA_DEBUG & DEBUG_VERBOSE_MSG)
mgaDDPrintDirty( __FUNCTION__, mmesa->dirty );
if (mmesa->dirty & MGA_UPLOAD_CONTEXT) {
mmesa->setup.wflag = _CULL_DISABLE;
if (mmesa->raster_primitive == GL_TRIANGLES) {
if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) {
mmesa->setup.wflag = mmesa->hw.cull_dualtex;
}
else {
mmesa->setup.wflag = mmesa->hw.cull;
}
}
mmesa->setup.stencil = mmesa->hw.stencil
& mmesa->hw.stencil_enable;
mmesa->setup.stencilctl = mmesa->hw.stencilctl
& mmesa->hw.stencil_enable;
/* If depth testing is not enabled, then use the no Z-compare / no
* Z-write mode. Otherwise, use whatever is set in hw.zmode.
*/
mmesa->setup.dwgctl &= (DC_zmode_MASK & DC_atype_MASK);
mmesa->setup.dwgctl |= (ctx->Depth.Test)
? mmesa->hw.zmode : (DC_zmode_nozcmp | DC_atype_i);
mmesa->setup.dwgctl &= DC_bop_MASK;
mmesa->setup.dwgctl |= RGBA_LOGICOP_ENABLED(ctx)
? mmesa->hw.rop : mgarop_NoBLK[ GL_COPY & 0x0f ];
mmesa->setup.alphactrl &= AC_src_MASK & AC_dst_MASK & AC_atmode_MASK
& AC_atref_MASK & AC_alphasel_MASK;
mmesa->setup.alphactrl |=
(mmesa->hw.alpha_func & mmesa->hw.alpha_func_enable) |
(mmesa->hw.blend_func & mmesa->hw.blend_func_enable) |
((AC_src_one | AC_dst_zero) & ~mmesa->hw.blend_func_enable) |
mmesa->hw.alpha_sel;
memcpy( &sarea->context_state, &mmesa->setup, sizeof(mmesa->setup));
}
if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) {
memcpy(&sarea->tex_state[0],
&mmesa->CurrentTexObj[0]->setup,
sizeof(sarea->tex_state[0]));
}
if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) {
memcpy(&sarea->tex_state[1],
&mmesa->CurrentTexObj[1]->setup,
sizeof(sarea->tex_state[1]));
}
if (mmesa->dirty & (MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1)) {
sarea->tex_state[0].texctl2 &= ~TMC_specen_enable;
sarea->tex_state[1].texctl2 &= ~TMC_specen_enable;
sarea->tex_state[0].texctl2 |= mmesa->hw.specen;
sarea->tex_state[1].texctl2 |= mmesa->hw.specen;
}
if (mmesa->dirty & MGA_UPLOAD_PIPE) {
/* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */
mmesa->sarea->warp_pipe = mmesa->vertex_format;
mmesa->sarea->vertsize = mmesa->vertex_size;
}
mmesa->sarea->dirty |= mmesa->dirty;
mmesa->dirty &= MGA_UPLOAD_CLIPRECTS;
}
/* =============================================================
*/
static void mgaDDValidateState( GLcontext *ctx )
{
mgaContextPtr mmesa = MGA_CONTEXT( ctx );
FLUSH_BATCH( mmesa );
if (mmesa->NewGLState & _NEW_TEXTURE) {
mgaUpdateTextureState(ctx);
}
if (!mmesa->Fallback) {
if (mmesa->NewGLState & _MGA_NEW_RASTERSETUP) {
mgaChooseVertexState( ctx );
}
if (mmesa->NewGLState & _MGA_NEW_RENDERSTATE) {
mgaChooseRenderState( ctx );
}
}
mmesa->NewGLState = 0;
}
static void mgaDDInvalidateState( GLcontext *ctx, GLuint new_state )
{
_swrast_InvalidateState( ctx, new_state );
_swsetup_InvalidateState( ctx, new_state );
_vbo_InvalidateState( ctx, new_state );
_tnl_InvalidateState( ctx, new_state );
MGA_CONTEXT(ctx)->NewGLState |= new_state;
}
static void mgaRunPipeline( GLcontext *ctx )
{
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
if (mmesa->NewGLState) {
mgaDDValidateState( ctx );
}
if (mmesa->dirty) {
mgaEmitHwStateLocked( mmesa );
}
_tnl_run_pipeline( ctx );
}
void mgaInitState( mgaContextPtr mmesa )
{
mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
GLcontext *ctx = mmesa->glCtx;
if (ctx->Visual.doubleBufferMode) {
/* use back buffer by default */
mmesa->draw_buffer = MGA_BACK;
mmesa->drawOffset = mmesa->mgaScreen->backOffset;
mmesa->readOffset = mmesa->mgaScreen->backOffset;
mmesa->setup.dstorg = mgaScreen->backOffset;
} else {
/* use front buffer by default */
mmesa->draw_buffer = MGA_FRONT;
mmesa->drawOffset = mmesa->mgaScreen->frontOffset;
mmesa->readOffset = mmesa->mgaScreen->frontOffset;
mmesa->setup.dstorg = mgaScreen->frontOffset;
}
mmesa->setup.maccess = (MA_memreset_disable |
MA_fogen_disable |
MA_tlutload_disable |
MA_nodither_disable |
MA_dit555_disable);
if (driQueryOptioni (&mmesa->optionCache, "color_reduction") !=
DRI_CONF_COLOR_REDUCTION_DITHER)
mmesa->setup.maccess |= MA_nodither_enable;
switch (mmesa->mgaScreen->cpp) {
case 2:
mmesa->setup.maccess |= MA_pwidth_16;
break;
case 4:
mmesa->setup.maccess |= MA_pwidth_32;
break;
default:
fprintf( stderr, "Error: unknown cpp %d, exiting...\n",
mmesa->mgaScreen->cpp );
exit( 1 );
}
switch (mmesa->glCtx->Visual.depthBits) {
case 16:
mmesa->setup.maccess |= MA_zwidth_16;
break;
case 24:
mmesa->setup.maccess |= MA_zwidth_24;
break;
case 32:
mmesa->setup.maccess |= MA_zwidth_32;
break;
}
mmesa->hw.blend_func = AC_src_one | AC_dst_zero;
mmesa->hw.blend_func_enable = 0;
mmesa->hw.alpha_func = AC_atmode_noacmp | MGA_FIELD( AC_atref, 0x00 );
mmesa->hw.alpha_func_enable = 0;
mmesa->hw.rop = mgarop_NoBLK[ GL_COPY & 0x0f ];
mmesa->hw.zmode = DC_zmode_zlt | DC_atype_zi;
mmesa->hw.stencil = MGA_FIELD( S_sref, 0x00) | MGA_FIELD( S_smsk, 0xff ) |
MGA_FIELD( S_swtmsk, 0xff );
mmesa->hw.stencilctl = SC_smode_salways | SC_sfailop_keep
| SC_szfailop_keep | SC_szpassop_keep;
mmesa->hw.stencil_enable = 0;
mmesa->hw.cull = _CULL_DISABLE;
mmesa->hw.cull_dualtex = _CULL_DISABLE;
mmesa->hw.specen = 0;
mmesa->hw.alpha_sel = AC_alphasel_diffused;
mmesa->setup.dwgctl = (DC_opcod_trap |
DC_linear_xy |
DC_solid_disable |
DC_arzero_disable |
DC_sgnzero_disable |
DC_shftzero_enable |
MGA_FIELD( DC_bop, 0xC ) |
MGA_FIELD( DC_trans, 0x0 ) |
DC_bltmod_bmonolef |
DC_pattern_disable |
DC_transc_disable |
DC_clipdis_disable);
mmesa->setup.plnwt = ~0;
mmesa->setup.alphactrl = (AC_amode_alpha_channel |
AC_astipple_disable |
AC_aten_disable);
mmesa->setup.fogcolor = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F),
(GLubyte)(ctx->Fog.Color[1]*255.0F),
(GLubyte)(ctx->Fog.Color[2]*255.0F));
mmesa->setup.wflag = 0;
mmesa->setup.tdualstage0 = 0;
mmesa->setup.tdualstage1 = 0;
mmesa->setup.fcol = 0;
mmesa->dirty |= MGA_UPLOAD_CONTEXT;
mmesa->envcolor[0] = 0;
mmesa->envcolor[1] = 0;
}
void mgaDDInitStateFuncs( GLcontext *ctx )
{
ctx->Driver.UpdateState = mgaDDInvalidateState;
ctx->Driver.Enable = mgaDDEnable;
ctx->Driver.LightModelfv = mgaDDLightModelfv;
ctx->Driver.AlphaFunc = mgaDDAlphaFunc;
ctx->Driver.BlendEquationSeparate = mgaDDBlendEquationSeparate;
ctx->Driver.BlendFuncSeparate = mgaDDBlendFuncSeparate;
ctx->Driver.DepthFunc = mgaDDDepthFunc;
ctx->Driver.DepthMask = mgaDDDepthMask;
ctx->Driver.Fogfv = mgaDDFogfv;
ctx->Driver.Scissor = mgaDDScissor;
ctx->Driver.CullFace = mgaDDCullFaceFrontFace;
ctx->Driver.FrontFace = mgaDDCullFaceFrontFace;
ctx->Driver.ColorMask = mgaDDColorMask;
ctx->Driver.DrawBuffer = mgaDDDrawBuffer;
ctx->Driver.ReadBuffer = mgaDDReadBuffer;
ctx->Driver.ClearColor = mgaDDClearColor;
ctx->Driver.ClearDepth = mgaDDClearDepth;
ctx->Driver.LogicOpcode = mgaDDLogicOp;
ctx->Driver.PolygonStipple = mgaDDPolygonStipple;
ctx->Driver.StencilFuncSeparate = mgaDDStencilFuncSeparate;
ctx->Driver.StencilMaskSeparate = mgaDDStencilMaskSeparate;
ctx->Driver.StencilOpSeparate = mgaDDStencilOpSeparate;
ctx->Driver.DepthRange = mgaDepthRange;
ctx->Driver.Viewport = mgaViewport;
ctx->Driver.RenderMode = mgaRenderMode;
ctx->Driver.ClearIndex = 0;
ctx->Driver.IndexMask = 0;
TNL_CONTEXT(ctx)->Driver.RunPipeline = mgaRunPipeline;
}