summaryrefslogtreecommitdiffstats
path: root/src/mesa/drivers/dri/radeon/radeon_ioctl.c
diff options
context:
space:
mode:
authorDave Airlie <[email protected]>2009-03-06 16:05:22 +1000
committerDave Airlie <[email protected]>2009-03-06 16:07:23 +1000
commitc6ac53bc40508ab2f0b9e023eee7ec3793fdf917 (patch)
treea2b16905431da3b2da9d240928b007366eeb162a /src/mesa/drivers/dri/radeon/radeon_ioctl.c
parentb074aacdb2a9e3520ccd6cfd892b60599ad0d1d8 (diff)
radeon: implement userspace clears
This is pretty much Eric Anholts implementation of clear using the GL state machine from the Intel drivers. It works quite well for now for us, probably could do with trying to use Z engine for clears.
Diffstat (limited to 'src/mesa/drivers/dri/radeon/radeon_ioctl.c')
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_ioctl.c252
1 files changed, 223 insertions, 29 deletions
diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.c b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
index 6a24fc45ae6..22584f4817a 100644
--- a/src/mesa/drivers/dri/radeon/radeon_ioctl.c
+++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.c
@@ -37,6 +37,20 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <sched.h>
#include <errno.h>
+#include "main/attrib.h"
+#include "main/enable.h"
+#include "main/blend.h"
+#include "main/bufferobj.h"
+#include "main/buffers.h"
+#include "main/depth.h"
+#include "main/shaders.h"
+#include "main/texstate.h"
+#include "main/varray.h"
+#include "glapi/dispatch.h"
+#include "swrast/swrast.h"
+#include "main/stencil.h"
+#include "main/matrix.h"
+
#include "main/glheader.h"
#include "main/imports.h"
#include "main/simple_list.h"
@@ -405,42 +419,221 @@ void radeonEmitAOS( r100ContextPtr rmesa,
*/
#define RADEON_MAX_CLEARS 256
-static void radeonUserClear(GLcontext *ctx, GLuint flags)
+
+
+static void
+r100_meta_set_passthrough_transform(r100ContextPtr r100)
{
- GLuint mask = 0;
+ GLcontext *ctx = r100->radeon.glCtx;
- if (flags & RADEON_FRONT)
- mask |= BUFFER_BIT_FRONT_LEFT;
+ r100->meta.saved_vp_x = ctx->Viewport.X;
+ r100->meta.saved_vp_y = ctx->Viewport.Y;
+ r100->meta.saved_vp_width = ctx->Viewport.Width;
+ r100->meta.saved_vp_height = ctx->Viewport.Height;
+ r100->meta.saved_matrix_mode = ctx->Transform.MatrixMode;
- if (flags & RADEON_BACK)
- mask |= BUFFER_BIT_BACK_LEFT;
+ _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
- if (flags & RADEON_DEPTH)
- mask |= BUFFER_BIT_DEPTH;
+ _mesa_MatrixMode(GL_PROJECTION);
+ _mesa_PushMatrix();
+ _mesa_LoadIdentity();
+ _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1);
- if (flags & RADEON_STENCIL)
- mask |= BUFFER_BIT_STENCIL;
+ _mesa_MatrixMode(GL_MODELVIEW);
+ _mesa_PushMatrix();
+ _mesa_LoadIdentity();
+}
-#if 1
- _swrast_Clear(ctx, mask);
-#else
- for ( i = 0 ; i < dPriv->numClipRects ; ) {
+static void
+r100_meta_restore_transform(r100ContextPtr r100)
+{
+ _mesa_MatrixMode(GL_PROJECTION);
+ _mesa_PopMatrix();
+ _mesa_MatrixMode(GL_MODELVIEW);
+ _mesa_PopMatrix();
- }
+ _mesa_MatrixMode(r100->meta.saved_matrix_mode);
- if (flags & (RADEON_FRONT | RADEON_BACK)) {
- OUT_BATCH(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
- OUT_BATCH((RADEON_WAIT_3D_IDLECLEAN |
- RADEON_WAIT_HOST_IDLECLEAN));
- OUT_BATCH_REGVAL(RADEON_DP_WRITE_MASK, 0); //clear->color_mask);
+ _mesa_Viewport(r100->meta.saved_vp_x, r100->meta.saved_vp_y,
+ r100->meta.saved_vp_width, r100->meta.saved_vp_height);
+}
+/**
+ * Perform glClear where mask contains only color, depth, and/or stencil.
+ *
+ * The implementation is based on calling into Mesa to set GL state and
+ * performing normal triangle rendering. The intent of this path is to
+ * have as generic a path as possible, so that any driver could make use of
+ * it.
+ */
+static void radeon_clear_tris(GLcontext *ctx, GLbitfield mask)
+{
+ r100ContextPtr rmesa = R100_CONTEXT(ctx);
+ GLfloat vertices[4][3];
+ GLfloat color[4][4];
+ GLfloat dst_z;
+ struct gl_framebuffer *fb = ctx->DrawBuffer;
+ int i;
+ GLboolean saved_fp_enable = GL_FALSE, saved_vp_enable = GL_FALSE;
+ GLboolean saved_shader_program = 0;
+ unsigned int saved_active_texture;
+
+ assert((mask & ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_FRONT_LEFT |
+ BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) == 0);
+
+ _mesa_PushAttrib(GL_COLOR_BUFFER_BIT |
+ GL_CURRENT_BIT |
+ GL_DEPTH_BUFFER_BIT |
+ GL_ENABLE_BIT |
+ GL_STENCIL_BUFFER_BIT |
+ GL_TRANSFORM_BIT |
+ GL_CURRENT_BIT);
+ _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+ saved_active_texture = ctx->Texture.CurrentUnit;
+
+ /* Disable existing GL state we don't want to apply to a clear. */
+ _mesa_Disable(GL_ALPHA_TEST);
+ _mesa_Disable(GL_BLEND);
+ _mesa_Disable(GL_CULL_FACE);
+ _mesa_Disable(GL_FOG);
+ _mesa_Disable(GL_POLYGON_SMOOTH);
+ _mesa_Disable(GL_POLYGON_STIPPLE);
+ _mesa_Disable(GL_POLYGON_OFFSET_FILL);
+ _mesa_Disable(GL_LIGHTING);
+ _mesa_Disable(GL_CLIP_PLANE0);
+ _mesa_Disable(GL_CLIP_PLANE1);
+ _mesa_Disable(GL_CLIP_PLANE2);
+ _mesa_Disable(GL_CLIP_PLANE3);
+ _mesa_Disable(GL_CLIP_PLANE4);
+ _mesa_Disable(GL_CLIP_PLANE5);
+ if (ctx->Extensions.ARB_fragment_program && ctx->FragmentProgram.Enabled) {
+ saved_fp_enable = GL_TRUE;
+ _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB);
+ }
+ if (ctx->Extensions.ARB_vertex_program && ctx->VertexProgram.Enabled) {
+ saved_vp_enable = GL_TRUE;
+ _mesa_Disable(GL_VERTEX_PROGRAM_ARB);
+ }
+ if (ctx->Extensions.ARB_shader_objects && ctx->Shader.CurrentProgram) {
+ saved_shader_program = ctx->Shader.CurrentProgram->Name;
+ _mesa_UseProgramObjectARB(0);
+ }
+
+ if (ctx->Texture._EnabledUnits != 0) {
+ int i;
+
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ _mesa_ActiveTextureARB(GL_TEXTURE0 + i);
+ _mesa_Disable(GL_TEXTURE_1D);
+ _mesa_Disable(GL_TEXTURE_2D);
+ _mesa_Disable(GL_TEXTURE_3D);
+ if (ctx->Extensions.ARB_texture_cube_map)
+ _mesa_Disable(GL_TEXTURE_CUBE_MAP_ARB);
+ if (ctx->Extensions.NV_texture_rectangle)
+ _mesa_Disable(GL_TEXTURE_RECTANGLE_NV);
+ if (ctx->Extensions.MESA_texture_array) {
+ _mesa_Disable(GL_TEXTURE_1D_ARRAY_EXT);
+ _mesa_Disable(GL_TEXTURE_2D_ARRAY_EXT);
+ }
+ }
}
-
- if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
- && (flags & RADEON_CLEAR_FASTZ)) {
+
+ r100_meta_set_passthrough_transform(rmesa);
+
+ for (i = 0; i < 4; i++) {
+ color[i][0] = ctx->Color.ClearColor[0];
+ color[i][1] = ctx->Color.ClearColor[1];
+ color[i][2] = ctx->Color.ClearColor[2];
+ color[i][3] = ctx->Color.ClearColor[3];
+ }
+
+ /* convert clear Z from [0,1] to NDC coord in [-1,1] */
+ dst_z = -1.0 + 2.0 * ctx->Depth.Clear;
+
+ /* Prepare the vertices, which are the same regardless of which buffer we're
+ * drawing to.
+ */
+ vertices[0][0] = fb->_Xmin;
+ vertices[0][1] = fb->_Ymin;
+ vertices[0][2] = dst_z;
+ vertices[1][0] = fb->_Xmax;
+ vertices[1][1] = fb->_Ymin;
+ vertices[1][2] = dst_z;
+ vertices[2][0] = fb->_Xmax;
+ vertices[2][1] = fb->_Ymax;
+ vertices[2][2] = dst_z;
+ vertices[3][0] = fb->_Xmin;
+ vertices[3][1] = fb->_Ymax;
+ vertices[3][2] = dst_z;
+
+ _mesa_ColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &color);
+ _mesa_VertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), &vertices);
+ _mesa_Enable(GL_COLOR_ARRAY);
+ _mesa_Enable(GL_VERTEX_ARRAY);
+
+ while (mask != 0) {
+ GLuint this_mask = 0;
+
+ if (mask & BUFFER_BIT_BACK_LEFT)
+ this_mask = BUFFER_BIT_BACK_LEFT;
+ else if (mask & BUFFER_BIT_FRONT_LEFT)
+ this_mask = BUFFER_BIT_FRONT_LEFT;
+
+ /* Clear depth/stencil in the same pass as color. */
+ this_mask |= (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL));
+
+ /* Select the current color buffer and use the color write mask if
+ * we have one, otherwise don't write any color channels.
+ */
+ if (this_mask & BUFFER_BIT_FRONT_LEFT)
+ _mesa_DrawBuffer(GL_FRONT_LEFT);
+ else if (this_mask & BUFFER_BIT_BACK_LEFT)
+ _mesa_DrawBuffer(GL_BACK_LEFT);
+ else
+ _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* Control writing of the depth clear value to depth. */
+ if (this_mask & BUFFER_BIT_DEPTH) {
+ _mesa_DepthFunc(GL_ALWAYS);
+ _mesa_Enable(GL_DEPTH_TEST);
+ } else {
+ _mesa_Disable(GL_DEPTH_TEST);
+ _mesa_DepthMask(GL_FALSE);
+ }
+
+ /* Control writing of the stencil clear value to stencil. */
+ if (this_mask & BUFFER_BIT_STENCIL) {
+ _mesa_Enable(GL_STENCIL_TEST);
+ _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ _mesa_StencilFuncSeparate(GL_FRONT, GL_ALWAYS, ctx->Stencil.Clear,
+ ctx->Stencil.WriteMask[0]);
+ } else {
+ _mesa_Disable(GL_STENCIL_TEST);
+ }
+
+ CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4));
+ mask &= ~this_mask;
}
-#endif
+
+ r100_meta_restore_transform(rmesa);
+
+ _mesa_ActiveTextureARB(GL_TEXTURE0 + saved_active_texture);
+ if (saved_fp_enable)
+ _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB);
+ if (saved_vp_enable)
+ _mesa_Enable(GL_VERTEX_PROGRAM_ARB);
+
+ if (saved_shader_program)
+ _mesa_UseProgramObjectARB(saved_shader_program);
+
+ _mesa_PopClientAttrib();
+ _mesa_PopAttrib();
+}
+
+static void radeonUserClear(GLcontext *ctx, GLuint mask)
+{
+ radeon_clear_tris(ctx, mask);
}
static void radeonKernelClear(GLcontext *ctx, GLuint flags)
@@ -570,6 +763,7 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
__DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
GLuint flags = 0;
GLuint color_mask = 0;
+ GLuint orig_mask = mask;
if ( RADEON_DEBUG & DEBUG_IOCTL ) {
fprintf( stderr, "radeonClear\n");
@@ -582,7 +776,7 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
return;
}
- radeonFlush( ctx );
+ radeon_firevertices(&rmesa->radeon);
if ( mask & BUFFER_BIT_FRONT_LEFT ) {
flags |= RADEON_FRONT;
@@ -627,11 +821,11 @@ static void radeonClear( GLcontext *ctx, GLbitfield mask )
}
if (rmesa->radeon.radeonScreen->kernel_mm)
- radeonUserClear(ctx, flags);
- else
+ radeonUserClear(ctx, orig_mask);
+ else {
radeonKernelClear(ctx, flags);
-
- rmesa->radeon.hw.all_dirty = GL_TRUE;
+ rmesa->radeon.hw.all_dirty = GL_TRUE;
+ }
}
void radeonInitIoctlFuncs( GLcontext *ctx )