vc4_context.c revision af69d88d
1/* 2 * Copyright © 2014 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include <xf86drm.h> 25#include <err.h> 26#include <stdio.h> 27 28#include "pipe/p_defines.h" 29#include "util/u_inlines.h" 30#include "util/u_memory.h" 31#include "util/u_blitter.h" 32#include "indices/u_primconvert.h" 33#include "pipe/p_screen.h" 34 35#include "vc4_screen.h" 36#include "vc4_context.h" 37#include "vc4_resource.h" 38 39static void 40vc4_setup_rcl(struct vc4_context *vc4) 41{ 42 struct vc4_surface *csurf = vc4_surface(vc4->framebuffer.cbufs[0]); 43 struct vc4_resource *ctex = vc4_resource(csurf->base.texture); 44 uint32_t resolve_uncleared = vc4->resolve & ~vc4->cleared; 45 uint32_t width = vc4->framebuffer.width; 46 uint32_t height = vc4->framebuffer.height; 47 uint32_t xtiles = align(width, 64) / 64; 48 uint32_t ytiles = align(height, 64) / 64; 49 50#if 0 51 fprintf(stderr, "RCL: resolve 0x%x clear 0x%x resolve uncleared 0x%x\n", 52 vc4->resolve, 53 vc4->cleared, 54 resolve_uncleared); 55#endif 56 57 cl_u8(&vc4->rcl, VC4_PACKET_CLEAR_COLORS); 58 cl_u32(&vc4->rcl, vc4->clear_color[0]); 59 cl_u32(&vc4->rcl, vc4->clear_color[1]); 60 cl_u32(&vc4->rcl, vc4->clear_depth); 61 cl_u8(&vc4->rcl, 0); 62 63 cl_start_reloc(&vc4->rcl, 1); 64 cl_u8(&vc4->rcl, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); 65 cl_reloc(vc4, &vc4->rcl, ctex->bo, csurf->offset); 66 cl_u16(&vc4->rcl, width); 67 cl_u16(&vc4->rcl, height); 68 cl_u16(&vc4->rcl, ((ctex->tiling << 69 VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT) | 70 VC4_RENDER_CONFIG_FORMAT_RGBA8888 | 71 VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE)); 72 73 /* The tile buffer normally gets cleared when the previous tile is 74 * stored. If the clear values changed between frames, then the tile 75 * buffer has stale clear values in it, so we have to do a store in 76 * None mode (no writes) so that we trigger the tile buffer clear. 77 */ 78 if (vc4->cleared & PIPE_CLEAR_COLOR0) { 79 cl_u8(&vc4->rcl, VC4_PACKET_TILE_COORDINATES); 80 cl_u8(&vc4->rcl, 0); 81 cl_u8(&vc4->rcl, 0); 82 83 cl_u8(&vc4->rcl, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); 84 cl_u16(&vc4->rcl, VC4_LOADSTORE_TILE_BUFFER_NONE); 85 cl_u32(&vc4->rcl, 0); /* no address, since we're in None mode */ 86 } 87 88 for (int y = 0; y < ytiles; y++) { 89 for (int x = 0; x < xtiles; x++) { 90 bool end_of_frame = (x == xtiles - 1 && 91 y == ytiles - 1); 92 93 /* Note that the load doesn't actually occur until the 94 * tile coords packet is processed. 95 */ 96 if (resolve_uncleared & PIPE_CLEAR_COLOR) { 97 cl_start_reloc(&vc4->rcl, 1); 98 cl_u8(&vc4->rcl, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); 99 cl_u8(&vc4->rcl, 100 VC4_LOADSTORE_TILE_BUFFER_COLOR | 101 (ctex->tiling << 102 VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT)); 103 cl_u8(&vc4->rcl, 104 VC4_LOADSTORE_TILE_BUFFER_RGBA8888); 105 cl_reloc(vc4, &vc4->rcl, ctex->bo, 106 csurf->offset); 107 } 108 109 cl_u8(&vc4->rcl, VC4_PACKET_TILE_COORDINATES); 110 cl_u8(&vc4->rcl, x); 111 cl_u8(&vc4->rcl, y); 112 113 cl_start_reloc(&vc4->rcl, 1); 114 cl_u8(&vc4->rcl, VC4_PACKET_BRANCH_TO_SUB_LIST); 115 cl_reloc(vc4, &vc4->rcl, vc4->tile_alloc, 116 (y * xtiles + x) * 32); 117 118 if (vc4->resolve & PIPE_CLEAR_COLOR0) { 119 if (end_of_frame) { 120 cl_u8(&vc4->rcl, 121 VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF); 122 } else { 123 cl_u8(&vc4->rcl, 124 VC4_PACKET_STORE_MS_TILE_BUFFER); 125 } 126 } else { 127 assert(!"unfinished: Need to end the frame\n"); 128 } 129 } 130 } 131} 132 133void 134vc4_flush(struct pipe_context *pctx) 135{ 136 struct vc4_context *vc4 = vc4_context(pctx); 137 138 if (!vc4->needs_flush) 139 return; 140 141 cl_u8(&vc4->bcl, VC4_PACKET_FLUSH_ALL); 142 cl_u8(&vc4->bcl, VC4_PACKET_NOP); 143 cl_u8(&vc4->bcl, VC4_PACKET_HALT); 144 145 vc4_setup_rcl(vc4); 146 147 struct drm_vc4_submit_cl submit; 148 memset(&submit, 0, sizeof(submit)); 149 150 submit.bo_handles = vc4->bo_handles.base; 151 submit.bo_handle_count = (vc4->bo_handles.next - 152 vc4->bo_handles.base) / 4; 153 submit.bin_cl = vc4->bcl.base; 154 submit.bin_cl_size = vc4->bcl.next - vc4->bcl.base; 155 submit.render_cl = vc4->rcl.base; 156 submit.render_cl_size = vc4->rcl.next - vc4->rcl.base; 157 submit.shader_rec = vc4->shader_rec.base; 158 submit.shader_rec_size = vc4->shader_rec.next - vc4->shader_rec.base; 159 submit.shader_rec_count = vc4->shader_rec_count; 160 submit.uniforms = vc4->uniforms.base; 161 submit.uniforms_size = vc4->uniforms.next - vc4->uniforms.base; 162 163 if (!(vc4_debug & VC4_DEBUG_NORAST)) { 164 int ret; 165 166#ifndef USE_VC4_SIMULATOR 167 ret = drmIoctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); 168#else 169 ret = vc4_simulator_flush(vc4, &submit); 170#endif 171 if (ret) 172 errx(1, "VC4 submit failed\n"); 173 } 174 175 vc4_reset_cl(&vc4->bcl); 176 vc4_reset_cl(&vc4->rcl); 177 vc4_reset_cl(&vc4->shader_rec); 178 vc4_reset_cl(&vc4->uniforms); 179 vc4_reset_cl(&vc4->bo_handles); 180 struct vc4_bo **referenced_bos = vc4->bo_pointers.base; 181 for (int i = 0; i < submit.bo_handle_count; i++) 182 vc4_bo_unreference(&referenced_bos[i]); 183 vc4_reset_cl(&vc4->bo_pointers); 184 vc4->shader_rec_count = 0; 185 186 vc4->needs_flush = false; 187 vc4->draw_call_queued = false; 188 vc4->dirty = ~0; 189 vc4->resolve = 0; 190 vc4->cleared = 0; 191} 192 193static void 194vc4_pipe_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, 195 unsigned flags) 196{ 197 vc4_flush(pctx); 198} 199 200/** 201 * Flushes the current command lists if they reference the given BO. 202 * 203 * This helps avoid flushing the command buffers when unnecessary. 204 */ 205void 206vc4_flush_for_bo(struct pipe_context *pctx, struct vc4_bo *bo) 207{ 208 struct vc4_context *vc4 = vc4_context(pctx); 209 210 if (!vc4->needs_flush) 211 return; 212 213 /* Walk all the referenced BOs in the drawing command list to see if 214 * they match. 215 */ 216 struct vc4_bo **referenced_bos = vc4->bo_pointers.base; 217 for (int i = 0; i < (vc4->bo_handles.next - 218 vc4->bo_handles.base) / 4; i++) { 219 if (referenced_bos[i] == bo) { 220 vc4_flush(pctx); 221 return; 222 } 223 } 224 225 /* Also check for the Z/color buffers, since the references to those 226 * are only added immediately before submit. 227 */ 228 struct vc4_surface *csurf = vc4_surface(vc4->framebuffer.cbufs[0]); 229 if (csurf) { 230 struct vc4_resource *ctex = vc4_resource(csurf->base.texture); 231 if (ctex->bo == bo) { 232 vc4_flush(pctx); 233 return; 234 } 235 } 236 237 struct vc4_surface *zsurf = vc4_surface(vc4->framebuffer.zsbuf); 238 if (zsurf) { 239 struct vc4_resource *ztex = 240 vc4_resource(zsurf->base.texture); 241 if (ztex->bo == bo) { 242 vc4_flush(pctx); 243 return; 244 } 245 } 246} 247 248static void 249vc4_context_destroy(struct pipe_context *pctx) 250{ 251 struct vc4_context *vc4 = vc4_context(pctx); 252 253 if (vc4->blitter) 254 util_blitter_destroy(vc4->blitter); 255 256 if (vc4->primconvert) 257 util_primconvert_destroy(vc4->primconvert); 258 259 util_slab_destroy(&vc4->transfer_pool); 260 261 free(vc4); 262} 263 264struct pipe_context * 265vc4_context_create(struct pipe_screen *pscreen, void *priv) 266{ 267 struct vc4_screen *screen = vc4_screen(pscreen); 268 struct vc4_context *vc4; 269 270 /* Prevent dumping of the shaders built during context setup. */ 271 uint32_t saved_shaderdb_flag = vc4_debug & VC4_DEBUG_SHADERDB; 272 vc4_debug &= ~VC4_DEBUG_SHADERDB; 273 274 vc4 = CALLOC_STRUCT(vc4_context); 275 if (vc4 == NULL) 276 return NULL; 277 struct pipe_context *pctx = &vc4->base; 278 279 vc4->screen = screen; 280 281 pctx->screen = pscreen; 282 pctx->priv = priv; 283 pctx->destroy = vc4_context_destroy; 284 pctx->flush = vc4_pipe_flush; 285 286 vc4_draw_init(pctx); 287 vc4_state_init(pctx); 288 vc4_program_init(pctx); 289 vc4_resource_context_init(pctx); 290 291 vc4_init_cl(vc4, &vc4->bcl); 292 vc4_init_cl(vc4, &vc4->rcl); 293 vc4_init_cl(vc4, &vc4->shader_rec); 294 vc4_init_cl(vc4, &vc4->bo_handles); 295 296 vc4->dirty = ~0; 297 vc4->fd = screen->fd; 298 299 util_slab_create(&vc4->transfer_pool, sizeof(struct pipe_transfer), 300 16, UTIL_SLAB_SINGLETHREADED); 301 vc4->blitter = util_blitter_create(pctx); 302 if (!vc4->blitter) 303 goto fail; 304 305 vc4->primconvert = util_primconvert_create(pctx, 306 (1 << PIPE_PRIM_QUADS) - 1); 307 if (!vc4->primconvert) 308 goto fail; 309 310 vc4_debug |= saved_shaderdb_flag; 311 312 return &vc4->base; 313 314fail: 315 pctx->destroy(pctx); 316 return NULL; 317} 318