727 lines
20 KiB
C
727 lines
20 KiB
C
/**************************************************************************
|
|
|
|
Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
|
|
|
|
The Weather Channel (TM) funded Tungsten Graphics to develop the
|
|
initial release of the Radeon 8500 driver under the XFree86 license.
|
|
This notice must be preserved.
|
|
|
|
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 (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 NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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 <keithw@vmware.com>
|
|
*/
|
|
|
|
/*
|
|
- Scissor implementation
|
|
- buffer swap/copy ioctls
|
|
- finish/flush
|
|
- state emission
|
|
- cmdbuffer management
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include "main/glheader.h"
|
|
#include "main/context.h"
|
|
#include "main/enums.h"
|
|
#include "main/fbobject.h"
|
|
#include "main/framebuffer.h"
|
|
#include "main/renderbuffer.h"
|
|
#include "drivers/common/meta.h"
|
|
|
|
#include "radeon_common.h"
|
|
#include "radeon_drm.h"
|
|
#include "radeon_queryobj.h"
|
|
|
|
/**
|
|
* Enable verbose debug output for emit code.
|
|
* 0 no output
|
|
* 1 most output
|
|
* 2 also print state alues
|
|
*/
|
|
#define RADEON_CMDBUF 0
|
|
|
|
/* =============================================================
|
|
* Scissoring
|
|
*/
|
|
|
|
/**
|
|
* Update cliprects and scissors.
|
|
*/
|
|
void radeonSetCliprects(radeonContextPtr radeon)
|
|
{
|
|
__DRIdrawable *const drawable = radeon_get_drawable(radeon);
|
|
__DRIdrawable *const readable = radeon_get_readable(radeon);
|
|
|
|
if(drawable == NULL && readable == NULL)
|
|
return;
|
|
|
|
struct radeon_framebuffer *const draw_rfb = drawable->driverPrivate;
|
|
struct radeon_framebuffer *const read_rfb = readable->driverPrivate;
|
|
|
|
if ((draw_rfb->base.Width != drawable->w) ||
|
|
(draw_rfb->base.Height != drawable->h)) {
|
|
_mesa_resize_framebuffer(&radeon->glCtx, &draw_rfb->base,
|
|
drawable->w, drawable->h);
|
|
}
|
|
|
|
if (drawable != readable) {
|
|
if ((read_rfb->base.Width != readable->w) ||
|
|
(read_rfb->base.Height != readable->h)) {
|
|
_mesa_resize_framebuffer(&radeon->glCtx, &read_rfb->base,
|
|
readable->w, readable->h);
|
|
}
|
|
}
|
|
|
|
if (radeon->state.scissor.enabled)
|
|
radeonUpdateScissor(&radeon->glCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void radeonUpdateScissor( struct gl_context *ctx )
|
|
{
|
|
radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
|
|
GLint x = ctx->Scissor.ScissorArray[0].X, y = ctx->Scissor.ScissorArray[0].Y;
|
|
GLsizei w = ctx->Scissor.ScissorArray[0].Width, h = ctx->Scissor.ScissorArray[0].Height;
|
|
int x1, y1, x2, y2;
|
|
int min_x, min_y, max_x, max_y;
|
|
|
|
if (!ctx->DrawBuffer)
|
|
return;
|
|
min_x = min_y = 0;
|
|
max_x = ctx->DrawBuffer->Width - 1;
|
|
max_y = ctx->DrawBuffer->Height - 1;
|
|
|
|
if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
|
|
x1 = x;
|
|
y1 = ctx->DrawBuffer->Height - (y + h);
|
|
x2 = x + w - 1;
|
|
y2 = y1 + h - 1;
|
|
} else {
|
|
x1 = x;
|
|
y1 = y;
|
|
x2 = x + w - 1;
|
|
y2 = y + h - 1;
|
|
|
|
}
|
|
|
|
rmesa->state.scissor.rect.x1 = CLAMP(x1, min_x, max_x);
|
|
rmesa->state.scissor.rect.y1 = CLAMP(y1, min_y, max_y);
|
|
rmesa->state.scissor.rect.x2 = CLAMP(x2, min_x, max_x);
|
|
rmesa->state.scissor.rect.y2 = CLAMP(y2, min_y, max_y);
|
|
|
|
if (rmesa->vtbl.update_scissor)
|
|
rmesa->vtbl.update_scissor(ctx);
|
|
}
|
|
|
|
/* =============================================================
|
|
* Scissoring
|
|
*/
|
|
|
|
void radeonScissor(struct gl_context *ctx)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
if (ctx->Scissor.EnableFlags) {
|
|
/* We don't pipeline cliprect changes */
|
|
radeon_firevertices(radeon);
|
|
radeonUpdateScissor(ctx);
|
|
}
|
|
}
|
|
|
|
/* ================================================================
|
|
* SwapBuffers with client-side throttling
|
|
*/
|
|
|
|
uint32_t radeonGetAge(radeonContextPtr radeon)
|
|
{
|
|
drm_radeon_getparam_t gp;
|
|
int ret;
|
|
uint32_t age;
|
|
|
|
gp.param = RADEON_PARAM_LAST_CLEAR;
|
|
gp.value = (int *)&age;
|
|
ret = drmCommandWriteRead(radeon->radeonScreen->driScreen->fd, DRM_RADEON_GETPARAM,
|
|
&gp, sizeof(gp));
|
|
if (ret) {
|
|
fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __func__,
|
|
ret);
|
|
exit(1);
|
|
}
|
|
|
|
return age;
|
|
}
|
|
|
|
void radeon_draw_buffer(struct gl_context *ctx, struct gl_framebuffer *fb)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
struct radeon_renderbuffer *rrbDepth = NULL, *rrbStencil = NULL,
|
|
*rrbColor = NULL;
|
|
uint32_t offset = 0;
|
|
|
|
|
|
if (!fb) {
|
|
/* this can happen during the initial context initialization */
|
|
return;
|
|
}
|
|
|
|
/* radeons only handle 1 color draw so far */
|
|
if (fb->_NumColorDrawBuffers != 1) {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DRAW_BUFFER, GL_TRUE);
|
|
return;
|
|
}
|
|
|
|
/* Do this here, note core Mesa, since this function is called from
|
|
* many places within the driver.
|
|
*/
|
|
if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
|
|
/* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
|
|
_mesa_update_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer);
|
|
/* this updates the DrawBuffer's Width/Height if it's a FBO */
|
|
_mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
|
|
}
|
|
|
|
if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
|
/* this may occur when we're called by glBindFrameBuffer() during
|
|
* the process of someone setting up renderbuffers, etc.
|
|
*/
|
|
/*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
|
|
return;
|
|
}
|
|
|
|
if (fb->Name) {
|
|
;/* do something depthy/stencily TODO */
|
|
}
|
|
|
|
/* none */
|
|
if (fb->Name == 0) {
|
|
if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) {
|
|
rrbColor = radeon_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
|
|
radeon->front_cliprects = GL_TRUE;
|
|
} else {
|
|
rrbColor = radeon_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
|
|
radeon->front_cliprects = GL_FALSE;
|
|
}
|
|
} else {
|
|
/* user FBO in theory */
|
|
struct radeon_renderbuffer *rrb;
|
|
rrb = radeon_renderbuffer(fb->_ColorDrawBuffers[0]);
|
|
if (rrb) {
|
|
offset = rrb->draw_offset;
|
|
rrbColor = rrb;
|
|
}
|
|
}
|
|
|
|
if (rrbColor == NULL)
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DRAW_BUFFER, GL_TRUE);
|
|
else
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE);
|
|
|
|
|
|
if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
|
|
rrbDepth = radeon_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
|
|
if (rrbDepth && rrbDepth->bo) {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DEPTH_BUFFER, GL_FALSE);
|
|
} else {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DEPTH_BUFFER, GL_TRUE);
|
|
}
|
|
} else {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_DEPTH_BUFFER, GL_FALSE);
|
|
rrbDepth = NULL;
|
|
}
|
|
|
|
if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
|
|
rrbStencil = radeon_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
|
|
if (rrbStencil && rrbStencil->bo) {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_STENCIL_BUFFER, GL_FALSE);
|
|
/* need to re-compute stencil hw state */
|
|
if (!rrbDepth)
|
|
rrbDepth = rrbStencil;
|
|
} else {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_STENCIL_BUFFER, GL_TRUE);
|
|
}
|
|
} else {
|
|
radeon->vtbl.fallback(ctx, RADEON_FALLBACK_STENCIL_BUFFER, GL_FALSE);
|
|
if (ctx->Driver.Enable != NULL)
|
|
ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
|
|
else
|
|
ctx->NewState |= _NEW_STENCIL;
|
|
}
|
|
|
|
/* Update culling direction which changes depending on the
|
|
* orientation of the buffer:
|
|
*/
|
|
if (ctx->Driver.FrontFace)
|
|
ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
|
|
else
|
|
ctx->NewState |= _NEW_POLYGON;
|
|
|
|
/*
|
|
* Update depth test state
|
|
*/
|
|
if (ctx->Driver.Enable) {
|
|
ctx->Driver.Enable(ctx, GL_DEPTH_TEST,
|
|
(ctx->Depth.Test && fb->Visual.depthBits > 0));
|
|
ctx->Driver.Enable(ctx, GL_STENCIL_TEST,
|
|
(ctx->Stencil.Enabled && fb->Visual.stencilBits > 0));
|
|
} else {
|
|
ctx->NewState |= (_NEW_DEPTH | _NEW_STENCIL);
|
|
}
|
|
|
|
_mesa_reference_renderbuffer(&radeon->state.depth.rb, &rrbDepth->base.Base);
|
|
_mesa_reference_renderbuffer(&radeon->state.color.rb, &rrbColor->base.Base);
|
|
radeon->state.color.draw_offset = offset;
|
|
|
|
ctx->NewState |= _NEW_VIEWPORT;
|
|
|
|
/* Set state we know depends on drawable parameters:
|
|
*/
|
|
radeonUpdateScissor(ctx);
|
|
radeon->NewGLState |= _NEW_SCISSOR;
|
|
|
|
if (ctx->Driver.DepthRange)
|
|
ctx->Driver.DepthRange(ctx);
|
|
|
|
/* Update culling direction which changes depending on the
|
|
* orientation of the buffer:
|
|
*/
|
|
if (ctx->Driver.FrontFace)
|
|
ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
|
|
else
|
|
ctx->NewState |= _NEW_POLYGON;
|
|
}
|
|
|
|
/**
|
|
* Called via glDrawBuffer.
|
|
*/
|
|
void radeonDrawBuffer(struct gl_context *ctx)
|
|
{
|
|
if (RADEON_DEBUG & RADEON_DRI)
|
|
fprintf(stderr, "%s\n", __func__);
|
|
|
|
if (_mesa_is_front_buffer_drawing(ctx->DrawBuffer)) {
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
|
|
/* If we might be front-buffer rendering on this buffer for
|
|
* the first time, invalidate our DRI drawable so we'll ask
|
|
* for new buffers (including the fake front) before we start
|
|
* rendering again.
|
|
*/
|
|
radeon_update_renderbuffers(radeon->driContext,
|
|
radeon->driContext->driDrawablePriv,
|
|
GL_FALSE);
|
|
}
|
|
|
|
radeon_draw_buffer(ctx, ctx->DrawBuffer);
|
|
}
|
|
|
|
void radeonReadBuffer( struct gl_context *ctx, GLenum mode )
|
|
{
|
|
if (_mesa_is_front_buffer_reading(ctx->ReadBuffer)) {
|
|
struct radeon_context *const rmesa = RADEON_CONTEXT(ctx);
|
|
radeon_update_renderbuffers(rmesa->driContext,
|
|
rmesa->driContext->driReadablePriv, GL_FALSE);
|
|
}
|
|
/* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
|
|
if (ctx->ReadBuffer == ctx->DrawBuffer) {
|
|
/* This will update FBO completeness status.
|
|
* A framebuffer will be incomplete if the GL_READ_BUFFER setting
|
|
* refers to a missing renderbuffer. Calling glReadBuffer can set
|
|
* that straight and can make the drawing buffer complete.
|
|
*/
|
|
radeon_draw_buffer(ctx, ctx->DrawBuffer);
|
|
}
|
|
}
|
|
|
|
void radeon_window_moved(radeonContextPtr radeon)
|
|
{
|
|
/* Cliprects has to be updated before doing anything else */
|
|
radeonSetCliprects(radeon);
|
|
}
|
|
|
|
void radeon_viewport(struct gl_context *ctx)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
__DRIcontext *driContext = radeon->driContext;
|
|
void (*old_viewport)(struct gl_context *ctx);
|
|
|
|
if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
|
|
if (_mesa_is_front_buffer_drawing(ctx->DrawBuffer)) {
|
|
ctx->Driver.Flush(ctx, 0);
|
|
}
|
|
radeon_update_renderbuffers(driContext, driContext->driDrawablePriv, GL_FALSE);
|
|
if (driContext->driDrawablePriv != driContext->driReadablePriv)
|
|
radeon_update_renderbuffers(driContext, driContext->driReadablePriv, GL_FALSE);
|
|
}
|
|
|
|
old_viewport = ctx->Driver.Viewport;
|
|
ctx->Driver.Viewport = NULL;
|
|
radeon_window_moved(radeon);
|
|
radeon_draw_buffer(ctx, radeon->glCtx.DrawBuffer);
|
|
ctx->Driver.Viewport = old_viewport;
|
|
}
|
|
|
|
static void radeon_print_state_atom(radeonContextPtr radeon, struct radeon_state_atom *state)
|
|
{
|
|
int i, j, reg, count;
|
|
int dwords;
|
|
uint32_t packet0;
|
|
if (!radeon_is_debug_enabled(RADEON_STATE, RADEON_VERBOSE) )
|
|
return;
|
|
|
|
dwords = state->check(&radeon->glCtx, state);
|
|
|
|
fprintf(stderr, " emit %s %d/%d\n", state->name, dwords, state->cmd_size);
|
|
|
|
if (state->cmd && radeon_is_debug_enabled(RADEON_STATE, RADEON_TRACE)) {
|
|
if (dwords > state->cmd_size)
|
|
dwords = state->cmd_size;
|
|
for (i = 0; i < dwords;) {
|
|
packet0 = state->cmd[i];
|
|
reg = (packet0 & 0x1FFF) << 2;
|
|
count = ((packet0 & 0x3FFF0000) >> 16) + 1;
|
|
fprintf(stderr, " %s[%d]: cmdpacket0 (first reg=0x%04x, count=%d)\n",
|
|
state->name, i, reg, count);
|
|
++i;
|
|
for (j = 0; j < count && i < dwords; j++) {
|
|
fprintf(stderr, " %s[%d]: 0x%04x = %08x\n",
|
|
state->name, i, reg, state->cmd[i]);
|
|
reg += 4;
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Count total size for next state emit.
|
|
**/
|
|
GLuint radeonCountStateEmitSize(radeonContextPtr radeon)
|
|
{
|
|
struct radeon_state_atom *atom;
|
|
GLuint dwords = 0;
|
|
/* check if we are going to emit full state */
|
|
|
|
if (radeon->cmdbuf.cs->cdw && !radeon->hw.all_dirty) {
|
|
if (!radeon->hw.is_dirty)
|
|
goto out;
|
|
foreach(atom, &radeon->hw.atomlist) {
|
|
if (atom->dirty) {
|
|
const GLuint atom_size = atom->check(&radeon->glCtx, atom);
|
|
dwords += atom_size;
|
|
if (RADEON_CMDBUF && atom_size) {
|
|
radeon_print_state_atom(radeon, atom);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
foreach(atom, &radeon->hw.atomlist) {
|
|
const GLuint atom_size = atom->check(&radeon->glCtx, atom);
|
|
dwords += atom_size;
|
|
if (RADEON_CMDBUF && atom_size) {
|
|
radeon_print_state_atom(radeon, atom);
|
|
}
|
|
|
|
}
|
|
}
|
|
out:
|
|
radeon_print(RADEON_STATE, RADEON_NORMAL, "%s %u\n", __func__, dwords);
|
|
return dwords;
|
|
}
|
|
|
|
static inline void radeon_emit_atom(radeonContextPtr radeon, struct radeon_state_atom *atom)
|
|
{
|
|
BATCH_LOCALS(radeon);
|
|
int dwords;
|
|
|
|
dwords = atom->check(&radeon->glCtx, atom);
|
|
if (dwords) {
|
|
|
|
radeon_print_state_atom(radeon, atom);
|
|
|
|
if (atom->emit) {
|
|
atom->emit(&radeon->glCtx, atom);
|
|
} else {
|
|
BEGIN_BATCH(dwords);
|
|
OUT_BATCH_TABLE(atom->cmd, dwords);
|
|
END_BATCH();
|
|
}
|
|
atom->dirty = GL_FALSE;
|
|
|
|
} else {
|
|
radeon_print(RADEON_STATE, RADEON_VERBOSE, " skip state %s\n", atom->name);
|
|
}
|
|
|
|
}
|
|
|
|
static inline void radeonEmitAtoms(radeonContextPtr radeon, GLboolean emitAll)
|
|
{
|
|
struct radeon_state_atom *atom;
|
|
|
|
/* Emit actual atoms */
|
|
if (radeon->hw.all_dirty || emitAll) {
|
|
foreach(atom, &radeon->hw.atomlist)
|
|
radeon_emit_atom( radeon, atom );
|
|
} else {
|
|
foreach(atom, &radeon->hw.atomlist) {
|
|
if ( atom->dirty )
|
|
radeon_emit_atom( radeon, atom );
|
|
}
|
|
}
|
|
|
|
COMMIT_BATCH();
|
|
}
|
|
|
|
void radeonEmitState(radeonContextPtr radeon)
|
|
{
|
|
radeon_print(RADEON_STATE, RADEON_NORMAL, "%s\n", __func__);
|
|
|
|
if (radeon->vtbl.pre_emit_state)
|
|
radeon->vtbl.pre_emit_state(radeon);
|
|
|
|
/* this code used to return here but now it emits zbs */
|
|
if (radeon->cmdbuf.cs->cdw && !radeon->hw.is_dirty && !radeon->hw.all_dirty)
|
|
return;
|
|
|
|
if (!radeon->cmdbuf.cs->cdw) {
|
|
if (RADEON_DEBUG & RADEON_STATE)
|
|
fprintf(stderr, "Begin reemit state\n");
|
|
|
|
radeonEmitAtoms(radeon, GL_TRUE);
|
|
} else {
|
|
|
|
if (RADEON_DEBUG & RADEON_STATE)
|
|
fprintf(stderr, "Begin dirty state\n");
|
|
|
|
radeonEmitAtoms(radeon, GL_FALSE);
|
|
}
|
|
|
|
radeon->hw.is_dirty = GL_FALSE;
|
|
radeon->hw.all_dirty = GL_FALSE;
|
|
}
|
|
|
|
|
|
void radeonFlush(struct gl_context *ctx, unsigned gallium_flush_flags)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
if (RADEON_DEBUG & RADEON_IOCTL)
|
|
fprintf(stderr, "%s %d\n", __func__, radeon->cmdbuf.cs->cdw);
|
|
|
|
/* okay if we have no cmds in the buffer &&
|
|
we have no DMA flush &&
|
|
we have no DMA buffer allocated.
|
|
then no point flushing anything at all.
|
|
*/
|
|
if (!radeon->dma.flush && !radeon->cmdbuf.cs->cdw && is_empty_list(&radeon->dma.reserved))
|
|
goto flush_front;
|
|
|
|
if (radeon->dma.flush)
|
|
radeon->dma.flush( ctx );
|
|
|
|
if (radeon->cmdbuf.cs->cdw)
|
|
rcommonFlushCmdBuf(radeon, __func__);
|
|
|
|
flush_front:
|
|
if (_mesa_is_winsys_fbo(ctx->DrawBuffer) && radeon->front_buffer_dirty) {
|
|
__DRIscreen *const screen = radeon->radeonScreen->driScreen;
|
|
|
|
if (screen->dri2.loader && (screen->dri2.loader->base.version >= 2)
|
|
&& (screen->dri2.loader->flushFrontBuffer != NULL)) {
|
|
__DRIdrawable * drawable = radeon_get_drawable(radeon);
|
|
|
|
/* We set the dirty bit in radeon_prepare_render() if we're
|
|
* front buffer rendering once we get there.
|
|
*/
|
|
radeon->front_buffer_dirty = GL_FALSE;
|
|
|
|
screen->dri2.loader->flushFrontBuffer(drawable, drawable->loaderPrivate);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Make sure all commands have been sent to the hardware and have
|
|
* completed processing.
|
|
*/
|
|
void radeonFinish(struct gl_context * ctx)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
struct gl_framebuffer *fb = ctx->DrawBuffer;
|
|
struct radeon_renderbuffer *rrb;
|
|
int i;
|
|
|
|
if (ctx->Driver.Flush)
|
|
ctx->Driver.Flush(ctx, 0); /* +r6/r7 */
|
|
|
|
for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
|
|
struct radeon_renderbuffer *rrb;
|
|
rrb = radeon_renderbuffer(fb->_ColorDrawBuffers[i]);
|
|
if (rrb && rrb->bo)
|
|
radeon_bo_wait(rrb->bo);
|
|
}
|
|
rrb = radeon_get_depthbuffer(radeon);
|
|
if (rrb && rrb->bo)
|
|
radeon_bo_wait(rrb->bo);
|
|
}
|
|
|
|
/* cmdbuffer */
|
|
/**
|
|
* Send the current command buffer via ioctl to the hardware.
|
|
*/
|
|
int rcommonFlushCmdBufLocked(radeonContextPtr rmesa, const char *caller)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (rmesa->cmdbuf.flushing) {
|
|
fprintf(stderr, "Recursive call into r300FlushCmdBufLocked!\n");
|
|
exit(-1);
|
|
}
|
|
rmesa->cmdbuf.flushing = 1;
|
|
|
|
if (RADEON_DEBUG & RADEON_IOCTL) {
|
|
fprintf(stderr, "%s from %s\n", __func__, caller);
|
|
}
|
|
|
|
radeonEmitQueryEnd(&rmesa->glCtx);
|
|
|
|
if (rmesa->cmdbuf.cs->cdw) {
|
|
ret = radeon_cs_emit(rmesa->cmdbuf.cs);
|
|
rmesa->hw.all_dirty = GL_TRUE;
|
|
}
|
|
radeon_cs_erase(rmesa->cmdbuf.cs);
|
|
rmesa->cmdbuf.flushing = 0;
|
|
|
|
if (!rmesa->vtbl.revalidate_all_buffers(&rmesa->glCtx))
|
|
fprintf(stderr,"failed to revalidate buffers\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
int rcommonFlushCmdBuf(radeonContextPtr rmesa, const char *caller)
|
|
{
|
|
int ret;
|
|
|
|
radeonReleaseDmaRegions(rmesa);
|
|
|
|
ret = rcommonFlushCmdBufLocked(rmesa, caller);
|
|
|
|
if (ret) {
|
|
fprintf(stderr, "drmRadeonCmdBuffer: %d. Kernel failed to "
|
|
"parse or rejected command stream. See dmesg "
|
|
"for more info.\n", ret);
|
|
exit(ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Make sure that enough space is available in the command buffer
|
|
* by flushing if necessary.
|
|
*
|
|
* \param dwords The number of dwords we need to be free on the command buffer
|
|
*/
|
|
GLboolean rcommonEnsureCmdBufSpace(radeonContextPtr rmesa, int dwords, const char *caller)
|
|
{
|
|
if ((rmesa->cmdbuf.cs->cdw + dwords + 128) > rmesa->cmdbuf.size
|
|
|| radeon_cs_need_flush(rmesa->cmdbuf.cs)) {
|
|
/* If we try to flush empty buffer there is too big rendering operation. */
|
|
assert(rmesa->cmdbuf.cs->cdw);
|
|
rcommonFlushCmdBuf(rmesa, caller);
|
|
return GL_TRUE;
|
|
}
|
|
return GL_FALSE;
|
|
}
|
|
|
|
void rcommonInitCmdBuf(radeonContextPtr rmesa)
|
|
{
|
|
GLuint size;
|
|
struct drm_radeon_gem_info mminfo = { 0 };
|
|
int fd = rmesa->radeonScreen->driScreen->fd;
|
|
|
|
/* Initialize command buffer */
|
|
size = 256 * driQueryOptioni(&rmesa->optionCache,
|
|
"command_buffer_size");
|
|
if (size < 2 * rmesa->hw.max_state_size) {
|
|
size = 2 * rmesa->hw.max_state_size + 65535;
|
|
}
|
|
if (size > 64 * 256)
|
|
size = 64 * 256;
|
|
|
|
radeon_print(RADEON_CS, RADEON_VERBOSE,
|
|
"sizeof(drm_r300_cmd_header_t)=%zd\n", sizeof(drm_r300_cmd_header_t));
|
|
radeon_print(RADEON_CS, RADEON_VERBOSE,
|
|
"sizeof(drm_radeon_cmd_buffer_t)=%zd\n", sizeof(drm_radeon_cmd_buffer_t));
|
|
radeon_print(RADEON_CS, RADEON_VERBOSE,
|
|
"Allocating %d bytes command buffer (max state is %d bytes)\n",
|
|
size * 4, rmesa->hw.max_state_size * 4);
|
|
|
|
rmesa->cmdbuf.csm = radeon_cs_manager_gem_ctor(fd);
|
|
if (rmesa->cmdbuf.csm == NULL) {
|
|
/* FIXME: fatal error */
|
|
return;
|
|
}
|
|
rmesa->cmdbuf.cs = radeon_cs_create(rmesa->cmdbuf.csm, size);
|
|
assert(rmesa->cmdbuf.cs != NULL);
|
|
rmesa->cmdbuf.size = size;
|
|
|
|
radeon_cs_space_set_flush(rmesa->cmdbuf.cs,
|
|
(void (*)(void *))rmesa->glCtx.Driver.Flush, &rmesa->glCtx);
|
|
|
|
|
|
if (!drmCommandWriteRead(fd, DRM_RADEON_GEM_INFO,
|
|
&mminfo, sizeof(mminfo))) {
|
|
radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM,
|
|
mminfo.vram_visible);
|
|
radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT,
|
|
mminfo.gart_size);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroy the command buffer
|
|
*/
|
|
void rcommonDestroyCmdBuf(radeonContextPtr rmesa)
|
|
{
|
|
radeon_cs_destroy(rmesa->cmdbuf.cs);
|
|
radeon_cs_manager_gem_dtor(rmesa->cmdbuf.csm);
|
|
}
|
|
|
|
void rcommonBeginBatch(radeonContextPtr rmesa, int n,
|
|
const char *file,
|
|
const char *function,
|
|
int line)
|
|
{
|
|
radeon_cs_begin(rmesa->cmdbuf.cs, n, file, function, line);
|
|
|
|
radeon_print(RADEON_CS, RADEON_VERBOSE, "BEGIN_BATCH(%d) at %d, from %s:%i\n",
|
|
n, rmesa->cmdbuf.cs->cdw, function, line);
|
|
|
|
}
|
|
|
|
void radeonUserClear(struct gl_context *ctx, GLuint mask)
|
|
{
|
|
_mesa_meta_Clear(ctx, mask);
|
|
}
|