Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_draw.c
4570 views
/*1* Copyright (C) 2012 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "pipe/p_state.h"27#include "util/format/u_format.h"28#include "util/u_draw.h"29#include "util/u_helpers.h"30#include "util/u_memory.h"31#include "util/u_prim.h"32#include "util/u_string.h"3334#include "freedreno_blitter.h"35#include "freedreno_context.h"36#include "freedreno_draw.h"37#include "freedreno_fence.h"38#include "freedreno_query_acc.h"39#include "freedreno_query_hw.h"40#include "freedreno_resource.h"41#include "freedreno_state.h"42#include "freedreno_util.h"4344static void45resource_read(struct fd_batch *batch, struct pipe_resource *prsc) assert_dt46{47if (!prsc)48return;49fd_batch_resource_read(batch, fd_resource(prsc));50}5152static void53resource_written(struct fd_batch *batch, struct pipe_resource *prsc) assert_dt54{55if (!prsc)56return;57fd_batch_resource_write(batch, fd_resource(prsc));58}5960static void61batch_draw_tracking_for_dirty_bits(struct fd_batch *batch) assert_dt62{63struct fd_context *ctx = batch->ctx;64struct pipe_framebuffer_state *pfb = &batch->framebuffer;65unsigned buffers = 0, restore_buffers = 0;6667if (ctx->dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_ZSA)) {68if (fd_depth_enabled(ctx)) {69if (fd_resource(pfb->zsbuf->texture)->valid) {70restore_buffers |= FD_BUFFER_DEPTH;71} else {72batch->invalidated |= FD_BUFFER_DEPTH;73}74batch->gmem_reason |= FD_GMEM_DEPTH_ENABLED;75if (fd_depth_write_enabled(ctx)) {76buffers |= FD_BUFFER_DEPTH;77resource_written(batch, pfb->zsbuf->texture);78} else {79resource_read(batch, pfb->zsbuf->texture);80}81}8283if (fd_stencil_enabled(ctx)) {84if (fd_resource(pfb->zsbuf->texture)->valid) {85restore_buffers |= FD_BUFFER_STENCIL;86} else {87batch->invalidated |= FD_BUFFER_STENCIL;88}89batch->gmem_reason |= FD_GMEM_STENCIL_ENABLED;90buffers |= FD_BUFFER_STENCIL;91resource_written(batch, pfb->zsbuf->texture);92}93}9495if (ctx->dirty & FD_DIRTY_FRAMEBUFFER) {96for (unsigned i = 0; i < pfb->nr_cbufs; i++) {97struct pipe_resource *surf;9899if (!pfb->cbufs[i])100continue;101102surf = pfb->cbufs[i]->texture;103104if (fd_resource(surf)->valid) {105restore_buffers |= PIPE_CLEAR_COLOR0 << i;106} else {107batch->invalidated |= PIPE_CLEAR_COLOR0 << i;108}109110buffers |= PIPE_CLEAR_COLOR0 << i;111112if (ctx->dirty & FD_DIRTY_FRAMEBUFFER)113resource_written(batch, pfb->cbufs[i]->texture);114}115}116117if (ctx->dirty & FD_DIRTY_BLEND) {118if (ctx->blend->logicop_enable)119batch->gmem_reason |= FD_GMEM_LOGICOP_ENABLED;120for (unsigned i = 0; i < pfb->nr_cbufs; i++) {121if (ctx->blend->rt[i].blend_enable)122batch->gmem_reason |= FD_GMEM_BLEND_ENABLED;123}124}125126/* Mark SSBOs */127if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_SSBO) {128const struct fd_shaderbuf_stateobj *so =129&ctx->shaderbuf[PIPE_SHADER_FRAGMENT];130131u_foreach_bit (i, so->enabled_mask & so->writable_mask)132resource_written(batch, so->sb[i].buffer);133134u_foreach_bit (i, so->enabled_mask & ~so->writable_mask)135resource_read(batch, so->sb[i].buffer);136}137138if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_IMAGE) {139u_foreach_bit (i, ctx->shaderimg[PIPE_SHADER_FRAGMENT].enabled_mask) {140struct pipe_image_view *img =141&ctx->shaderimg[PIPE_SHADER_FRAGMENT].si[i];142if (img->access & PIPE_IMAGE_ACCESS_WRITE)143resource_written(batch, img->resource);144else145resource_read(batch, img->resource);146}147}148149u_foreach_bit (s, ctx->bound_shader_stages) {150/* Mark constbuf as being read: */151if (ctx->dirty_shader[s] & FD_DIRTY_SHADER_CONST) {152u_foreach_bit (i, ctx->constbuf[s].enabled_mask)153resource_read(batch, ctx->constbuf[s].cb[i].buffer);154}155156/* Mark textures as being read */157if (ctx->dirty_shader[s] & FD_DIRTY_SHADER_TEX) {158u_foreach_bit (i, ctx->tex[s].valid_textures)159resource_read(batch, ctx->tex[s].textures[i]->texture);160}161}162163/* Mark VBOs as being read */164if (ctx->dirty & FD_DIRTY_VTXBUF) {165u_foreach_bit (i, ctx->vtx.vertexbuf.enabled_mask) {166assert(!ctx->vtx.vertexbuf.vb[i].is_user_buffer);167resource_read(batch, ctx->vtx.vertexbuf.vb[i].buffer.resource);168}169}170171/* Mark streamout buffers as being written.. */172if (ctx->dirty & FD_DIRTY_STREAMOUT) {173for (unsigned i = 0; i < ctx->streamout.num_targets; i++)174if (ctx->streamout.targets[i])175resource_written(batch, ctx->streamout.targets[i]->buffer);176}177178/* any buffers that haven't been cleared yet, we need to restore: */179batch->restore |= restore_buffers & (FD_BUFFER_ALL & ~batch->invalidated);180/* and any buffers used, need to be resolved: */181batch->resolve |= buffers;182}183184static void185batch_draw_tracking(struct fd_batch *batch, const struct pipe_draw_info *info,186const struct pipe_draw_indirect_info *indirect) assert_dt187{188struct fd_context *ctx = batch->ctx;189190/* NOTE: needs to be before resource_written(batch->query_buf), otherwise191* query_buf may not be created yet.192*/193fd_batch_update_queries(batch);194195/*196* Figure out the buffers/features we need:197*/198199fd_screen_lock(ctx->screen);200201if (ctx->dirty & FD_DIRTY_RESOURCE)202batch_draw_tracking_for_dirty_bits(batch);203204/* Mark index buffer as being read */205if (info->index_size)206resource_read(batch, info->index.resource);207208/* Mark indirect draw buffer as being read */209if (indirect) {210if (indirect->buffer)211resource_read(batch, indirect->buffer);212if (indirect->count_from_stream_output)213resource_read(214batch, fd_stream_output_target(indirect->count_from_stream_output)215->offset_buf);216}217218resource_written(batch, batch->query_buf);219220list_for_each_entry (struct fd_acc_query, aq, &ctx->acc_active_queries, node)221resource_written(batch, aq->prsc);222223fd_screen_unlock(ctx->screen);224}225226static void227update_draw_stats(struct fd_context *ctx, const struct pipe_draw_info *info,228const struct pipe_draw_start_count_bias *draws,229unsigned num_draws) assert_dt230{231ctx->stats.draw_calls++;232233if (ctx->screen->gpu_id < 600) {234/* Counting prims in sw doesn't work for GS and tesselation. For older235* gens we don't have those stages and don't have the hw counters enabled,236* so keep the count accurate for non-patch geometry.237*/238unsigned prims = 0;239if ((info->mode != PIPE_PRIM_PATCHES) && (info->mode != PIPE_PRIM_MAX)) {240for (unsigned i = 0; i < num_draws; i++) {241prims += u_reduced_prims_for_vertices(info->mode, draws[i].count);242}243}244245ctx->stats.prims_generated += prims;246247if (ctx->streamout.num_targets > 0) {248/* Clip the prims we're writing to the size of the SO buffers. */249enum pipe_prim_type tf_prim = u_decomposed_prim(info->mode);250unsigned verts_written = u_vertices_for_prims(tf_prim, prims);251unsigned remaining_vert_space =252ctx->streamout.max_tf_vtx - ctx->streamout.verts_written;253if (verts_written > remaining_vert_space) {254verts_written = remaining_vert_space;255u_trim_pipe_prim(tf_prim, &remaining_vert_space);256}257ctx->streamout.verts_written += verts_written;258259ctx->stats.prims_emitted +=260u_reduced_prims_for_vertices(tf_prim, verts_written);261}262}263}264265static void266fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,267unsigned drawid_offset,268const struct pipe_draw_indirect_info *indirect,269const struct pipe_draw_start_count_bias *draws, unsigned num_draws) in_dt270{271struct fd_context *ctx = fd_context(pctx);272273/* for debugging problems with indirect draw, it is convenient274* to be able to emulate it, to determine if game is feeding us275* bogus data:276*/277if (indirect && indirect->buffer && FD_DBG(NOINDR)) {278/* num_draws is only applicable for direct draws: */279assert(num_draws == 1);280util_draw_indirect(pctx, info, indirect);281return;282}283284/* TODO: push down the region versions into the tiles */285if (!fd_render_condition_check(pctx))286return;287288/* emulate unsupported primitives: */289if (!fd_supported_prim(ctx, info->mode)) {290if (ctx->streamout.num_targets > 0)291mesa_loge("stream-out with emulated prims");292util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);293util_primconvert_draw_vbo(ctx->primconvert, info, drawid_offset, indirect, draws,294num_draws);295return;296}297298/* Upload a user index buffer. */299struct pipe_resource *indexbuf = NULL;300unsigned index_offset = 0;301struct pipe_draw_info new_info;302if (info->index_size) {303if (info->has_user_indices) {304if (num_draws > 1) {305util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);306return;307}308if (!util_upload_index_buffer(pctx, info, &draws[0], &indexbuf,309&index_offset, 4))310return;311new_info = *info;312new_info.index.resource = indexbuf;313new_info.has_user_indices = false;314info = &new_info;315} else {316indexbuf = info->index.resource;317}318}319320if ((ctx->streamout.num_targets > 0) && (num_draws > 1)) {321util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);322return;323}324325struct fd_batch *batch = fd_context_batch(ctx);326327batch_draw_tracking(batch, info, indirect);328329while (unlikely(!fd_batch_lock_submit(batch))) {330/* The current batch was flushed in batch_draw_tracking()331* so start anew. We know this won't happen a second time332* since we are dealing with a fresh batch:333*/334fd_batch_reference(&batch, NULL);335batch = fd_context_batch(ctx);336batch_draw_tracking(batch, info, indirect);337assert(ctx->batch == batch);338}339340batch->num_draws++;341342/* Marking the batch as needing flush must come after the batch343* dependency tracking (resource_read()/resource_write()), as that344* can trigger a flush345*/346fd_batch_needs_flush(batch);347348struct pipe_framebuffer_state *pfb = &batch->framebuffer;349DBG("%p: %ux%u num_draws=%u (%s/%s)", batch, pfb->width, pfb->height,350batch->num_draws,351util_format_short_name(pipe_surface_format(pfb->cbufs[0])),352util_format_short_name(pipe_surface_format(pfb->zsbuf)));353354batch->cost += ctx->draw_cost;355356for (unsigned i = 0; i < num_draws; i++) {357ctx->draw_vbo(ctx, info, drawid_offset, indirect, &draws[i], index_offset);358359batch->num_vertices += draws[i].count * info->instance_count;360}361362if (unlikely(ctx->stats_users > 0))363update_draw_stats(ctx, info, draws, num_draws);364365for (unsigned i = 0; i < ctx->streamout.num_targets; i++) {366assert(num_draws == 1);367ctx->streamout.offsets[i] += draws[0].count;368}369370if (FD_DBG(DDRAW))371fd_context_all_dirty(ctx);372373debug_assert(!batch->flushed);374375fd_batch_unlock_submit(batch);376fd_batch_check_size(batch);377fd_batch_reference(&batch, NULL);378379if (info == &new_info)380pipe_resource_reference(&indexbuf, NULL);381}382383static void384batch_clear_tracking(struct fd_batch *batch, unsigned buffers) assert_dt385{386struct fd_context *ctx = batch->ctx;387struct pipe_framebuffer_state *pfb = &batch->framebuffer;388unsigned cleared_buffers;389390/* pctx->clear() is only for full-surface clears, so scissor is391* equivalent to having GL_SCISSOR_TEST disabled:392*/393batch->max_scissor.minx = 0;394batch->max_scissor.miny = 0;395batch->max_scissor.maxx = pfb->width;396batch->max_scissor.maxy = pfb->height;397398/* for bookkeeping about which buffers have been cleared (and thus399* can fully or partially skip mem2gmem) we need to ignore buffers400* that have already had a draw, in case apps do silly things like401* clear after draw (ie. if you only clear the color buffer, but402* something like alpha-test causes side effects from the draw in403* the depth buffer, etc)404*/405cleared_buffers = buffers & (FD_BUFFER_ALL & ~batch->restore);406batch->cleared |= buffers;407batch->invalidated |= cleared_buffers;408409batch->resolve |= buffers;410411fd_screen_lock(ctx->screen);412413if (buffers & PIPE_CLEAR_COLOR)414for (unsigned i = 0; i < pfb->nr_cbufs; i++)415if (buffers & (PIPE_CLEAR_COLOR0 << i))416resource_written(batch, pfb->cbufs[i]->texture);417418if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {419resource_written(batch, pfb->zsbuf->texture);420batch->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL;421}422423resource_written(batch, batch->query_buf);424425list_for_each_entry (struct fd_acc_query, aq, &ctx->acc_active_queries, node)426resource_written(batch, aq->prsc);427428fd_screen_unlock(ctx->screen);429}430431static void432fd_clear(struct pipe_context *pctx, unsigned buffers,433const struct pipe_scissor_state *scissor_state,434const union pipe_color_union *color, double depth,435unsigned stencil) in_dt436{437struct fd_context *ctx = fd_context(pctx);438439/* TODO: push down the region versions into the tiles */440if (!fd_render_condition_check(pctx))441return;442443struct fd_batch *batch = fd_context_batch(ctx);444445batch_clear_tracking(batch, buffers);446447while (unlikely(!fd_batch_lock_submit(batch))) {448/* The current batch was flushed in batch_clear_tracking()449* so start anew. We know this won't happen a second time450* since we are dealing with a fresh batch:451*/452fd_batch_reference(&batch, NULL);453batch = fd_context_batch(ctx);454batch_clear_tracking(batch, buffers);455assert(ctx->batch == batch);456}457458/* Marking the batch as needing flush must come after the batch459* dependency tracking (resource_read()/resource_write()), as that460* can trigger a flush461*/462fd_batch_needs_flush(batch);463464struct pipe_framebuffer_state *pfb = &batch->framebuffer;465DBG("%p: %x %ux%u depth=%f, stencil=%u (%s/%s)", batch, buffers, pfb->width,466pfb->height, depth, stencil,467util_format_short_name(pipe_surface_format(pfb->cbufs[0])),468util_format_short_name(pipe_surface_format(pfb->zsbuf)));469470/* if per-gen backend doesn't implement ctx->clear() generic471* blitter clear:472*/473bool fallback = true;474475if (ctx->clear) {476fd_batch_update_queries(batch);477478if (ctx->clear(ctx, buffers, color, depth, stencil)) {479if (FD_DBG(DCLEAR))480fd_context_all_dirty(ctx);481482fallback = false;483}484}485486debug_assert(!batch->flushed);487488fd_batch_unlock_submit(batch);489fd_batch_check_size(batch);490491if (fallback) {492fd_blitter_clear(pctx, buffers, color, depth, stencil);493}494495fd_batch_reference(&batch, NULL);496}497498static void499fd_clear_render_target(struct pipe_context *pctx, struct pipe_surface *ps,500const union pipe_color_union *color, unsigned x,501unsigned y, unsigned w, unsigned h,502bool render_condition_enabled)503{504DBG("TODO: x=%u, y=%u, w=%u, h=%u", x, y, w, h);505}506507static void508fd_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *ps,509unsigned buffers, double depth, unsigned stencil,510unsigned x, unsigned y, unsigned w, unsigned h,511bool render_condition_enabled)512{513DBG("TODO: buffers=%u, depth=%f, stencil=%u, x=%u, y=%u, w=%u, h=%u",514buffers, depth, stencil, x, y, w, h);515}516517static void518fd_launch_grid(struct pipe_context *pctx,519const struct pipe_grid_info *info) in_dt520{521struct fd_context *ctx = fd_context(pctx);522const struct fd_shaderbuf_stateobj *so =523&ctx->shaderbuf[PIPE_SHADER_COMPUTE];524struct fd_batch *batch, *save_batch = NULL;525526batch = fd_bc_alloc_batch(ctx, true);527fd_batch_reference(&save_batch, ctx->batch);528fd_batch_reference(&ctx->batch, batch);529fd_context_all_dirty(ctx);530531fd_screen_lock(ctx->screen);532533/* Mark SSBOs */534u_foreach_bit (i, so->enabled_mask & so->writable_mask)535resource_written(batch, so->sb[i].buffer);536537u_foreach_bit (i, so->enabled_mask & ~so->writable_mask)538resource_read(batch, so->sb[i].buffer);539540u_foreach_bit (i, ctx->shaderimg[PIPE_SHADER_COMPUTE].enabled_mask) {541struct pipe_image_view *img = &ctx->shaderimg[PIPE_SHADER_COMPUTE].si[i];542if (img->access & PIPE_IMAGE_ACCESS_WRITE)543resource_written(batch, img->resource);544else545resource_read(batch, img->resource);546}547548/* UBO's are read */549u_foreach_bit (i, ctx->constbuf[PIPE_SHADER_COMPUTE].enabled_mask)550resource_read(batch, ctx->constbuf[PIPE_SHADER_COMPUTE].cb[i].buffer);551552/* Mark textures as being read */553u_foreach_bit (i, ctx->tex[PIPE_SHADER_COMPUTE].valid_textures)554resource_read(batch, ctx->tex[PIPE_SHADER_COMPUTE].textures[i]->texture);555556/* For global buffers, we don't really know if read or written, so assume557* the worst:558*/559u_foreach_bit (i, ctx->global_bindings.enabled_mask)560resource_written(batch, ctx->global_bindings.buf[i]);561562if (info->indirect)563resource_read(batch, info->indirect);564565fd_screen_unlock(ctx->screen);566567DBG("%p: work_dim=%u, block=%ux%ux%u, grid=%ux%ux%u",568batch, info->work_dim,569info->block[0], info->block[1], info->block[2],570info->grid[0], info->grid[1], info->grid[2]);571572fd_batch_needs_flush(batch);573ctx->launch_grid(ctx, info);574575fd_batch_flush(batch);576577fd_batch_reference(&ctx->batch, save_batch);578fd_context_all_dirty(ctx);579fd_batch_reference(&save_batch, NULL);580fd_batch_reference(&batch, NULL);581}582583void584fd_draw_init(struct pipe_context *pctx)585{586pctx->draw_vbo = fd_draw_vbo;587pctx->clear = fd_clear;588pctx->clear_render_target = fd_clear_render_target;589pctx->clear_depth_stencil = fd_clear_depth_stencil;590591if (has_compute(fd_screen(pctx->screen))) {592pctx->launch_grid = fd_launch_grid;593}594}595596597