freedreno_draw.c revision 848b8605
1/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3/* 4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Rob Clark <robclark@freedesktop.org> 27 */ 28 29#include "pipe/p_state.h" 30#include "util/u_string.h" 31#include "util/u_memory.h" 32#include "util/u_prim.h" 33#include "util/u_format.h" 34 35#include "freedreno_draw.h" 36#include "freedreno_context.h" 37#include "freedreno_state.h" 38#include "freedreno_resource.h" 39#include "freedreno_query_hw.h" 40#include "freedreno_util.h" 41 42 43static void 44fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) 45{ 46 struct fd_context *ctx = fd_context(pctx); 47 struct pipe_framebuffer_state *pfb = &ctx->framebuffer; 48 struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx); 49 unsigned i, buffers = 0; 50 51 /* if we supported transform feedback, we'd have to disable this: */ 52 if (((scissor->maxx - scissor->minx) * 53 (scissor->maxy - scissor->miny)) == 0) { 54 return; 55 } 56 57 /* emulate unsupported primitives: */ 58 if (!fd_supported_prim(ctx, info->mode)) { 59 util_primconvert_save_index_buffer(ctx->primconvert, &ctx->indexbuf); 60 util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer); 61 util_primconvert_draw_vbo(ctx->primconvert, info); 62 return; 63 } 64 65 ctx->needs_flush = true; 66 67 /* 68 * Figure out the buffers/features we need: 69 */ 70 71 if (fd_depth_enabled(ctx)) { 72 buffers |= FD_BUFFER_DEPTH; 73 fd_resource(pfb->zsbuf->texture)->dirty = true; 74 ctx->gmem_reason |= FD_GMEM_DEPTH_ENABLED; 75 } 76 77 if (fd_stencil_enabled(ctx)) { 78 buffers |= FD_BUFFER_STENCIL; 79 fd_resource(pfb->zsbuf->texture)->dirty = true; 80 ctx->gmem_reason |= FD_GMEM_STENCIL_ENABLED; 81 } 82 83 if (fd_logicop_enabled(ctx)) 84 ctx->gmem_reason |= FD_GMEM_LOGICOP_ENABLED; 85 86 for (i = 0; i < pfb->nr_cbufs; i++) { 87 struct pipe_resource *surf; 88 89 if (!pfb->cbufs[i]) 90 continue; 91 92 surf = pfb->cbufs[i]->texture; 93 94 fd_resource(surf)->dirty = true; 95 buffers |= FD_BUFFER_COLOR; 96 97 if (surf->nr_samples > 1) 98 ctx->gmem_reason |= FD_GMEM_MSAA_ENABLED; 99 100 if (fd_blend_enabled(ctx, i)) 101 ctx->gmem_reason |= FD_GMEM_BLEND_ENABLED; 102 } 103 104 ctx->num_draws++; 105 106 ctx->stats.draw_calls++; 107 ctx->stats.prims_emitted += 108 u_reduced_prims_for_vertices(info->mode, info->count); 109 110 /* any buffers that haven't been cleared yet, we need to restore: */ 111 ctx->restore |= buffers & (FD_BUFFER_ALL & ~ctx->cleared); 112 /* and any buffers used, need to be resolved: */ 113 ctx->resolve |= buffers; 114 115 DBG("%x num_draws=%u (%s/%s)", buffers, ctx->num_draws, 116 util_format_short_name(pipe_surface_format(pfb->cbufs[0])), 117 util_format_short_name(pipe_surface_format(pfb->zsbuf))); 118 119 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_DRAW); 120 ctx->draw(ctx, info); 121 122 /* if an app (or, well, piglit test) does many thousands of draws 123 * without flush (or anything which implicitly flushes, like 124 * changing render targets), we can exceed the ringbuffer size. 125 * Since we don't currently have a sane way to wrapparound, and 126 * we use the same buffer for both draw and tiling commands, for 127 * now we need to do this hack and trigger flush if we are running 128 * low on remaining space for cmds: 129 */ 130 if (((ctx->ring->cur - ctx->ring->start) > 131 (ctx->ring->size/4 - FD_TILING_COMMANDS_DWORDS)) || 132 (fd_mesa_debug & FD_DBG_FLUSH)) 133 fd_context_render(pctx); 134} 135 136/* TODO figure out how to make better use of existing state mechanism 137 * for clear (and possibly gmem->mem / mem->gmem) so we can (a) keep 138 * track of what state really actually changes, and (b) reduce the code 139 * in the a2xx/a3xx parts. 140 */ 141 142static void 143fd_clear(struct pipe_context *pctx, unsigned buffers, 144 const union pipe_color_union *color, double depth, unsigned stencil) 145{ 146 struct fd_context *ctx = fd_context(pctx); 147 struct pipe_framebuffer_state *pfb = &ctx->framebuffer; 148 struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx); 149 unsigned cleared_buffers; 150 151 /* for bookkeeping about which buffers have been cleared (and thus 152 * can fully or partially skip mem2gmem) we need to ignore buffers 153 * that have already had a draw, in case apps do silly things like 154 * clear after draw (ie. if you only clear the color buffer, but 155 * something like alpha-test causes side effects from the draw in 156 * the depth buffer, etc) 157 */ 158 cleared_buffers = buffers & (FD_BUFFER_ALL & ~ctx->restore); 159 160 /* do we have full-screen scissor? */ 161 if (!memcmp(scissor, &ctx->disabled_scissor, sizeof(*scissor))) { 162 ctx->cleared |= cleared_buffers; 163 } else { 164 ctx->partial_cleared |= cleared_buffers; 165 if (cleared_buffers & PIPE_CLEAR_COLOR) 166 ctx->cleared_scissor.color = *scissor; 167 if (cleared_buffers & PIPE_CLEAR_DEPTH) 168 ctx->cleared_scissor.depth = *scissor; 169 if (cleared_buffers & PIPE_CLEAR_STENCIL) 170 ctx->cleared_scissor.stencil = *scissor; 171 } 172 ctx->resolve |= buffers; 173 ctx->needs_flush = true; 174 175 if (buffers & PIPE_CLEAR_COLOR) 176 fd_resource(pfb->cbufs[0]->texture)->dirty = true; 177 178 if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { 179 fd_resource(pfb->zsbuf->texture)->dirty = true; 180 ctx->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL; 181 } 182 183 DBG("%x depth=%f, stencil=%u (%s/%s)", buffers, depth, stencil, 184 util_format_short_name(pipe_surface_format(pfb->cbufs[0])), 185 util_format_short_name(pipe_surface_format(pfb->zsbuf))); 186 187 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_CLEAR); 188 189 ctx->clear(ctx, buffers, color, depth, stencil); 190 191 ctx->dirty |= FD_DIRTY_ZSA | 192 FD_DIRTY_VIEWPORT | 193 FD_DIRTY_RASTERIZER | 194 FD_DIRTY_SAMPLE_MASK | 195 FD_DIRTY_PROG | 196 FD_DIRTY_CONSTBUF | 197 FD_DIRTY_BLEND; 198 199 if (fd_mesa_debug & FD_DBG_DCLEAR) 200 ctx->dirty = 0xffffffff; 201} 202 203static void 204fd_clear_render_target(struct pipe_context *pctx, struct pipe_surface *ps, 205 const union pipe_color_union *color, 206 unsigned x, unsigned y, unsigned w, unsigned h) 207{ 208 DBG("TODO: x=%u, y=%u, w=%u, h=%u", x, y, w, h); 209} 210 211static void 212fd_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *ps, 213 unsigned buffers, double depth, unsigned stencil, 214 unsigned x, unsigned y, unsigned w, unsigned h) 215{ 216 DBG("TODO: buffers=%u, depth=%f, stencil=%u, x=%u, y=%u, w=%u, h=%u", 217 buffers, depth, stencil, x, y, w, h); 218} 219 220void 221fd_draw_init(struct pipe_context *pctx) 222{ 223 pctx->draw_vbo = fd_draw_vbo; 224 pctx->clear = fd_clear; 225 pctx->clear_render_target = fd_clear_render_target; 226 pctx->clear_depth_stencil = fd_clear_depth_stencil; 227} 228