emit_gmem2mem(struct fd_context *ctx, struct fd_ringbuffer *ring,
uint32_t xoff, uint32_t yoff, uint32_t bin_w, uint32_t bin_h)
{
- struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
- struct pipe_framebuffer_state *pfb = &fb->base;
+ struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
fd_emit_vertex_bufs(ring, 0x9c, (struct fd_vertex_buf[]) {
{ .prsc = ctx->solid_vertexbuf, .size = 48 },
emit_mem2gmem(struct fd_context *ctx, struct fd_ringbuffer *ring,
uint32_t xoff, uint32_t yoff, uint32_t bin_w, uint32_t bin_h)
{
- struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
- struct pipe_framebuffer_state *pfb = &fb->base;
+ struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
float x0, y0, x1, y1;
fd_emit_vertex_bufs(ring, 0x9c, (struct fd_vertex_buf[]) {
/* TODO blob driver seems to toss in a CACHE_FLUSH after each DRAW_INDX.. */
}
+static void
+calculate_tiles(struct fd_context *ctx)
+{
+ struct fd_gmem_stateobj *gmem = &ctx->gmem;
+ struct pipe_scissor_state *scissor = &ctx->max_scissor;
+ uint32_t cpp = util_format_get_blocksize(ctx->framebuffer.cbufs[0]->format);
+ uint32_t gmem_size = ctx->screen->gmemsize_bytes;
+ uint32_t minx, miny, width, height;
+ uint32_t nbins_x = 1, nbins_y = 1;
+ uint32_t bin_w, bin_h;
+ uint32_t max_width = 992;
+
+ if ((gmem->cpp == cpp) &&
+ !memcmp(&gmem->scissor, scissor, sizeof(gmem->scissor))) {
+ /* everything is up-to-date */
+ return;
+ }
+
+ minx = scissor->minx & ~31; /* round down to multiple of 32 */
+ miny = scissor->miny & ~31;
+ width = scissor->maxx - minx;
+ height = scissor->maxy - miny;
+
+// TODO we probably could optimize this a bit if we know that
+// Z or stencil is not enabled for any of the draw calls..
+// if (fd_stencil_enabled(ctx->zsa) || fd_depth_enabled(ctx->zsa)) {
+ gmem_size /= 2;
+ max_width = 256;
+// }
+
+ bin_w = ALIGN(width, 32);
+ bin_h = ALIGN(height, 32);
+
+ /* first, find a bin width that satisfies the maximum width
+ * restrictions:
+ */
+ while (bin_w > max_width) {
+ nbins_x++;
+ bin_w = ALIGN(width / nbins_x, 32);
+ }
+
+ /* then find a bin height that satisfies the memory constraints:
+ */
+ while ((bin_w * bin_h * cpp) > gmem_size) {
+ nbins_y++;
+ bin_h = ALIGN(height / nbins_y, 32);
+ }
+
+ DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
+
+ gmem->scissor = *scissor;
+ gmem->cpp = cpp;
+ gmem->minx = minx;
+ gmem->miny = miny;
+ gmem->bin_h = bin_h;
+ gmem->bin_w = bin_w;
+ gmem->nbins_x = nbins_x;
+ gmem->nbins_y = nbins_y;
+ gmem->width = width;
+ gmem->height = height;
+}
+
void
fd_gmem_render_tiles(struct pipe_context *pctx)
{
struct fd_context *ctx = fd_context(pctx);
- struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
- struct pipe_framebuffer_state *pfb = &fb->base;
- struct fd_ringbuffer *ring;
- uint32_t i, yoff = 0;
- uint32_t timestamp;
- ring = ctx->ring;
-
- DBG("rendering %dx%d tiles (%s/%s)", fb->nbins_x, fb->nbins_y,
+ struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+ struct fd_gmem_stateobj *gmem = &ctx->gmem;
+ struct fd_ringbuffer *ring = ctx->ring;
+ enum rb_colorformatx colorformatx = fd_pipe2color(pfb->cbufs[0]->format);
+ uint32_t i, timestamp, yoff = 0;
+ uint32_t base, reg;
+
+ calculate_tiles(ctx);
+
+ /* this should be true because bin_w/bin_h should be multiples of 32: */
+ assert(((gmem->bin_w * gmem->bin_h) % 1024) == 0);
+
+ /* depth/stencil starts after color buffer in GMEM: */
+ base = (gmem->bin_w * gmem->bin_h) / 1024;
+
+ DBG("rendering %dx%d tiles (%s/%s)", gmem->nbins_x, gmem->nbins_y,
util_format_name(pfb->cbufs[0]->format),
pfb->zsbuf ? util_format_name(pfb->zsbuf->format) : "none");
/* mark the end of the clear/draw cmds before emitting per-tile cmds: */
fd_ringmarker_mark(ctx->draw_end);
- for (i = 0; i < fb->nbins_y; i++) {
- uint32_t j, xoff = 0;
- uint32_t bin_h = fb->bin_h;
+ /* RB_SURFACE_INFO / RB_DEPTH_INFO can be emitted once per tile pass,
+ * but RB_COLOR_INFO gets overwritten by gmem2mem and mem2gmem and so
+ * needs to be emitted for each tile:
+ */
+ OUT_PKT3(ring, CP_SET_CONSTANT, 4);
+ OUT_RING(ring, CP_REG(REG_RB_SURFACE_INFO));
+ OUT_RING(ring, gmem->bin_w); /* RB_SURFACE_INFO */
+ OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
+ RB_COLOR_INFO_COLOR_FORMAT(colorformatx));
+ reg = RB_DEPTH_INFO_DEPTH_BASE(ALIGN(base, 4));
+ if (pfb->zsbuf)
+ reg |= RB_DEPTH_INFO_DEPTH_FORMAT(fd_pipe2depth(pfb->zsbuf->format));
+ OUT_RING(ring, reg); /* RB_DEPTH_INFO */
+
+ yoff= gmem->miny;
+ for (i = 0; i < gmem->nbins_y; i++) {
+ uint32_t j, xoff = gmem->minx;
+ uint32_t bh = gmem->bin_h;
/* clip bin height: */
- bin_h = min(bin_h, pfb->height - yoff);
+ bh = min(bh, gmem->height - yoff);
- for (j = 0; j < fb->nbins_x; j++) {
- uint32_t bin_w = fb->bin_w;
+ for (j = 0; j < gmem->nbins_x; j++) {
+ uint32_t bw = gmem->bin_w;
/* clip bin width: */
- bin_w = min(bin_w, pfb->width - xoff);
+ bw = min(bw, gmem->width - xoff);
DBG("bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
- bin_h, yoff, bin_w, xoff);
+ bh, yoff, bw, xoff);
+
+ if ((i == 0) && (j == 0)) {
+ uint32_t reg;
- fd_emit_framebuffer_state(ring, &ctx->framebuffer);
+
+ } else {
+
+ }
/* setup screen scissor for current tile (same for mem2gmem): */
OUT_PKT3(ring, CP_SET_CONSTANT, 3);
OUT_RING(ring, CP_REG(REG_PA_SC_SCREEN_SCISSOR_TL));
OUT_RING(ring, xy2d(0,0)); /* PA_SC_SCREEN_SCISSOR_TL */
- OUT_RING(ring, xy2d(bin_w, bin_h)); /* PA_SC_SCREEN_SCISSOR_BR */
+ OUT_RING(ring, xy2d(bw, bh)); /* PA_SC_SCREEN_SCISSOR_BR */
if (ctx->restore)
- emit_mem2gmem(ctx, ring, xoff, yoff, bin_w, bin_h);
+ emit_mem2gmem(ctx, ring, xoff, yoff, bw, bh);
+
+ OUT_PKT3(ring, CP_SET_CONSTANT, 2);
+ OUT_RING(ring, CP_REG(REG_RB_COLOR_INFO));
+ OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
+ RB_COLOR_INFO_COLOR_FORMAT(colorformatx));
/* setup window scissor and offset for current tile (different
* from mem2gmem):
OUT_RING(ring, 0x00000000); /* PA_SC_WINDOW_OFFSET */
/* emit gmem2mem to transfer tile back to system memory: */
- emit_gmem2mem(ctx, ring, xoff, yoff, bin_w, bin_h);
+ emit_gmem2mem(ctx, ring, xoff, yoff, bw, bh);
- xoff += bin_w;
+ xoff += bw;
}
- yoff += bin_h;
+ yoff += bh;
}
/* GPU executes starting from tile cmds, which IB back to draw cmds: */
if (pfb->zsbuf)
fd_resource(pfb->zsbuf->texture)->timestamp = timestamp;
+ /* reset maximal bounds: */
+ ctx->max_scissor.minx = ctx->max_scissor.miny = ~0;
+ ctx->max_scissor.maxx = ctx->max_scissor.maxy = 0;
+
/* Note that because the per-tile setup and mem2gmem/gmem2mem are emitted
* after the draw/clear calls, but executed before, we need to preemptively
* flag some state as dirty before the first draw/clear call.
FD_DIRTY_FRAGTEX |
FD_DIRTY_BLEND;
}
-
-void
-fd_gmem_calculate_tiles(struct pipe_context *pctx)
-{
- struct fd_context *ctx = fd_context(pctx);
- struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
- struct pipe_framebuffer_state *pfb = &fb->base;
- uint32_t nbins_x = 1, nbins_y = 1;
- uint32_t bin_w, bin_h;
- uint32_t cpp = util_format_get_blocksize(pfb->cbufs[0]->format);
- uint32_t gmem_size = ctx->screen->gmemsize_bytes;
- uint32_t max_width = 992;
-
-// TODO we probably could optimize this a bit if we know that
-// Z or stencil is not enabled for any of the draw calls..
-// if (fd_stencil_enabled(ctx->zsa) || fd_depth_enabled(ctx->zsa)) {
- gmem_size /= 2;
- max_width = 256;
-// }
-
- bin_w = ALIGN(pfb->width, 32);
- bin_h = ALIGN(pfb->height, 32);
-
- /* first, find a bin width that satisfies the maximum width
- * restrictions:
- */
- while (bin_w > max_width) {
- nbins_x++;
- bin_w = ALIGN(pfb->width / nbins_x, 32);
- }
-
- /* then find a bin height that satisfies the memory constraints:
- */
- while ((bin_w * bin_h * cpp) > gmem_size) {
- nbins_y++;
- bin_h = ALIGN(pfb->height / nbins_y, 32);
- }
-
- if ((nbins_x > 1) || (nbins_y > 1)) {
- fb->pa_su_sc_mode_cntl |= PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE;
- } else {
- fb->pa_su_sc_mode_cntl &= ~PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE;
- }
-
- DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
-
-//if we use hw binning, tile sizes (in multiple of 32) need to
-//fit in 5 bits.. for now don't care because we aren't using
-//that:
-// assert(!(bin_h/32 & ~0x1f));
-// assert(!(bin_w/32 & ~0x1f));
-
- fb->nbins_x = nbins_x;
- fb->nbins_y = nbins_y;
- fb->bin_w = bin_w;
- fb->bin_h = bin_h;
-
-}
const struct pipe_framebuffer_state *framebuffer)
{
struct fd_context *ctx = fd_context(pctx);
- struct pipe_framebuffer_state *cso = &ctx->framebuffer.base;
+ struct pipe_framebuffer_state *cso = &ctx->framebuffer;
unsigned i;
DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->needs_flush,
for (i = 0; i < framebuffer->nr_cbufs; i++)
pipe_surface_reference(&cso->cbufs[i], framebuffer->cbufs[i]);
- for (; i < ctx->framebuffer.base.nr_cbufs; i++)
+ for (; i < ctx->framebuffer.nr_cbufs; i++)
pipe_surface_reference(&cso->cbufs[i], NULL);
cso->nr_cbufs = framebuffer->nr_cbufs;
pipe_surface_reference(&cso->zsbuf, framebuffer->zsbuf);
- if (cso->nr_cbufs > 0)
- fd_gmem_calculate_tiles(pctx);
-
ctx->dirty |= FD_DIRTY_FRAMEBUFFER;
}
}
void
-fd_emit_framebuffer_state(struct fd_ringbuffer *ring,
- struct fd_framebuffer_stateobj *fb)
-{
- struct pipe_framebuffer_state *pfb = &fb->base;
- uint32_t reg, base;
-
- /* this should be true because bin_w/bin_h should be multiples of 32: */
- assert(((fb->bin_w * fb->bin_h) % 1024) == 0);
-
- /* depth/stencil starts after color buffer in GMEM: */
- base = (fb->bin_w * fb->bin_h) / 1024;
-
- OUT_PKT3(ring, CP_SET_CONSTANT, 4);
- OUT_RING(ring, CP_REG(REG_RB_SURFACE_INFO));
- OUT_RING(ring, fb->bin_w); /* RB_SURFACE_INFO */
- OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
- RB_COLOR_INFO_COLOR_FORMAT(fd_pipe2color(pfb->cbufs[0]->format)));
- reg = RB_DEPTH_INFO_DEPTH_BASE(ALIGN(base, 4));
- if (pfb->zsbuf)
- reg |= RB_DEPTH_INFO_DEPTH_FORMAT(fd_pipe2depth(pfb->zsbuf->format));
- OUT_RING(ring, reg); /* RB_DEPTH_INFO */
-}
-
-void
fd_state_emit(struct pipe_context *pctx, uint32_t dirty)
{
struct fd_context *ctx = fd_context(pctx);
OUT_RING(ring, CP_REG(REG_PA_CL_CLIP_CNTL));
OUT_RING(ring, ctx->rasterizer->pa_cl_clip_cntl);
OUT_RING(ring, ctx->rasterizer->pa_su_sc_mode_cntl |
- ctx->framebuffer.pa_su_sc_mode_cntl);
+ PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE);
OUT_PKT3(ring, CP_SET_CONSTANT, 5);
OUT_RING(ring, CP_REG(REG_PA_SU_POINT_SIZE));
OUT_RING(ring, f2d(1.0)); /* PA_CL_GB_HORZ_DISC_ADJ */
}
- if (dirty & FD_DIRTY_FRAMEBUFFER)
- fd_emit_framebuffer_state(ring, &ctx->framebuffer);
-
if (dirty & FD_DIRTY_SCISSOR) {
OUT_PKT3(ring, CP_SET_CONSTANT, 3);
OUT_RING(ring, CP_REG(REG_PA_SC_WINDOW_SCISSOR_TL));
ctx->scissor.miny));
OUT_RING(ring, xy2d(ctx->scissor.maxx, /* PA_SC_WINDOW_SCISSOR_BR */
ctx->scissor.maxy));
+
+ ctx->max_scissor.minx = min(ctx->max_scissor.minx, ctx->scissor.minx);
+ ctx->max_scissor.miny = min(ctx->max_scissor.miny, ctx->scissor.miny);
+ ctx->max_scissor.maxx = max(ctx->max_scissor.maxx, ctx->scissor.maxx);
+ ctx->max_scissor.maxy = max(ctx->max_scissor.maxy, ctx->scissor.maxy);
}
if (dirty & FD_DIRTY_VIEWPORT) {