1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3 /* 4 * Copyright (C) 2012 Rob Clark <robclark (at) 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 (at) freedesktop.org> 27 */ 28 29 #include "freedreno_context.h" 30 #include "freedreno_blitter.h" 31 #include "freedreno_draw.h" 32 #include "freedreno_fence.h" 33 #include "freedreno_program.h" 34 #include "freedreno_resource.h" 35 #include "freedreno_texture.h" 36 #include "freedreno_state.h" 37 #include "freedreno_gmem.h" 38 #include "freedreno_query.h" 39 #include "freedreno_query_hw.h" 40 #include "freedreno_util.h" 41 #include "util/u_upload_mgr.h" 42 43 static void 44 fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, 45 unsigned flags) 46 { 47 struct fd_context *ctx = fd_context(pctx); 48 struct pipe_fence_handle *fence = NULL; 49 50 /* Take a ref to the batch's fence (batch can be unref'd when flushed: */ 51 fd_fence_ref(pctx->screen, &fence, ctx->batch->fence); 52 53 if (flags & PIPE_FLUSH_FENCE_FD) 54 ctx->batch->needs_out_fence_fd = true; 55 56 if (!ctx->screen->reorder) { 57 fd_batch_flush(ctx->batch, true, false); 58 } else if (flags & PIPE_FLUSH_DEFERRED) { 59 fd_bc_flush_deferred(&ctx->screen->batch_cache, ctx); 60 } else { 61 fd_bc_flush(&ctx->screen->batch_cache, ctx); 62 } 63 64 if (fencep) 65 fd_fence_ref(pctx->screen, fencep, fence); 66 67 fd_fence_ref(pctx->screen, &fence, NULL); 68 } 69 70 static void 71 fd_texture_barrier(struct pipe_context *pctx, unsigned flags) 72 { 73 /* On devices that could sample from GMEM we could possibly do better. 74 * Or if we knew that we were doing GMEM bypass we could just emit a 75 * cache flush, perhaps? But we don't know if future draws would cause 76 * us to use GMEM, and a flush in bypass isn't the end of the world. 77 */ 78 fd_context_flush(pctx, NULL, 0); 79 } 80 81 /** 82 * emit marker string as payload of a no-op packet, which can be 83 * decoded by cffdump. 84 */ 85 static void 86 fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len) 87 { 88 struct fd_context *ctx = fd_context(pctx); 89 struct fd_ringbuffer *ring; 90 const uint32_t *buf = (const void *)string; 91 92 if (!ctx->batch) 93 return; 94 95 ring = ctx->batch->draw; 96 97 /* max packet size is 0x3fff dwords: */ 98 len = MIN2(len, 0x3fff * 4); 99 100 if (ctx->screen->gpu_id >= 500) 101 OUT_PKT7(ring, CP_NOP, align(len, 4) / 4); 102 else 103 OUT_PKT3(ring, CP_NOP, align(len, 4) / 4); 104 while (len >= 4) { 105 OUT_RING(ring, *buf); 106 buf++; 107 len -= 4; 108 } 109 110 /* copy remainder bytes without reading past end of input string: */ 111 if (len > 0) { 112 uint32_t w = 0; 113 memcpy(&w, buf, len); 114 OUT_RING(ring, w); 115 } 116 } 117 118 void 119 fd_context_destroy(struct pipe_context *pctx) 120 { 121 struct fd_context *ctx = fd_context(pctx); 122 unsigned i; 123 124 DBG(""); 125 126 if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue)) 127 util_queue_destroy(&ctx->flush_queue); 128 129 fd_batch_reference(&ctx->batch, NULL); /* unref current batch */ 130 fd_bc_invalidate_context(ctx); 131 132 fd_prog_fini(pctx); 133 134 if (ctx->blitter) 135 util_blitter_destroy(ctx->blitter); 136 137 if (pctx->stream_uploader) 138 u_upload_destroy(pctx->stream_uploader); 139 140 if (ctx->clear_rs_state) 141 pctx->delete_rasterizer_state(pctx, ctx->clear_rs_state); 142 143 if (ctx->primconvert) 144 util_primconvert_destroy(ctx->primconvert); 145 146 slab_destroy_child(&ctx->transfer_pool); 147 148 for (i = 0; i < ARRAY_SIZE(ctx->vsc_pipe); i++) { 149 struct fd_vsc_pipe *pipe = &ctx->vsc_pipe[i]; 150 if (!pipe->bo) 151 break; 152 fd_bo_del(pipe->bo); 153 } 154 155 fd_device_del(ctx->dev); 156 fd_pipe_del(ctx->pipe); 157 158 if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) { 159 printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, batch_restore=%u\n", 160 (uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem, 161 (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_nondraw, 162 (uint32_t)ctx->stats.batch_restore); 163 } 164 165 FREE(ctx); 166 } 167 168 static void 169 fd_set_debug_callback(struct pipe_context *pctx, 170 const struct pipe_debug_callback *cb) 171 { 172 struct fd_context *ctx = fd_context(pctx); 173 174 if (cb) 175 ctx->debug = *cb; 176 else 177 memset(&ctx->debug, 0, sizeof(ctx->debug)); 178 } 179 180 /* TODO we could combine a few of these small buffers (solid_vbuf, 181 * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and 182 * save a tiny bit of memory 183 */ 184 185 static struct pipe_resource * 186 create_solid_vertexbuf(struct pipe_context *pctx) 187 { 188 static const float init_shader_const[] = { 189 -1.000000, +1.000000, +1.000000, 190 +1.000000, -1.000000, +1.000000, 191 }; 192 struct pipe_resource *prsc = pipe_buffer_create(pctx->screen, 193 PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(init_shader_const)); 194 pipe_buffer_write(pctx, prsc, 0, 195 sizeof(init_shader_const), init_shader_const); 196 return prsc; 197 } 198 199 static struct pipe_resource * 200 create_blit_texcoord_vertexbuf(struct pipe_context *pctx) 201 { 202 struct pipe_resource *prsc = pipe_buffer_create(pctx->screen, 203 PIPE_BIND_CUSTOM, PIPE_USAGE_DYNAMIC, 16); 204 return prsc; 205 } 206 207 void 208 fd_context_setup_common_vbos(struct fd_context *ctx) 209 { 210 struct pipe_context *pctx = &ctx->base; 211 212 ctx->solid_vbuf = create_solid_vertexbuf(pctx); 213 ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx); 214 215 /* setup solid_vbuf_state: */ 216 ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state( 217 pctx, 1, (struct pipe_vertex_element[]){{ 218 .vertex_buffer_index = 0, 219 .src_offset = 0, 220 .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 221 }}); 222 ctx->solid_vbuf_state.vertexbuf.count = 1; 223 ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12; 224 ctx->solid_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->solid_vbuf; 225 226 /* setup blit_vbuf_state: */ 227 ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state( 228 pctx, 2, (struct pipe_vertex_element[]){{ 229 .vertex_buffer_index = 0, 230 .src_offset = 0, 231 .src_format = PIPE_FORMAT_R32G32_FLOAT, 232 }, { 233 .vertex_buffer_index = 1, 234 .src_offset = 0, 235 .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 236 }}); 237 ctx->blit_vbuf_state.vertexbuf.count = 2; 238 ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8; 239 ctx->blit_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->blit_texcoord_vbuf; 240 ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12; 241 ctx->blit_vbuf_state.vertexbuf.vb[1].buffer.resource = ctx->solid_vbuf; 242 } 243 244 void 245 fd_context_cleanup_common_vbos(struct fd_context *ctx) 246 { 247 struct pipe_context *pctx = &ctx->base; 248 249 pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx); 250 pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx); 251 252 pipe_resource_reference(&ctx->solid_vbuf, NULL); 253 pipe_resource_reference(&ctx->blit_texcoord_vbuf, NULL); 254 } 255 256 struct pipe_context * 257 fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, 258 const uint8_t *primtypes, void *priv, unsigned flags) 259 { 260 struct fd_screen *screen = fd_screen(pscreen); 261 struct pipe_context *pctx; 262 unsigned prio = 1; 263 int i; 264 265 /* lower numerical value == higher priority: */ 266 if (fd_mesa_debug & FD_DBG_HIPRIO) 267 prio = 0; 268 else if (flags & PIPE_CONTEXT_HIGH_PRIORITY) 269 prio = 0; 270 else if (flags & PIPE_CONTEXT_LOW_PRIORITY) 271 prio = 2; 272 273 ctx->screen = screen; 274 ctx->pipe = fd_pipe_new2(screen->dev, FD_PIPE_3D, prio); 275 276 ctx->primtypes = primtypes; 277 ctx->primtype_mask = 0; 278 for (i = 0; i < PIPE_PRIM_MAX; i++) 279 if (primtypes[i]) 280 ctx->primtype_mask |= (1 << i); 281 282 /* need some sane default in case state tracker doesn't 283 * set some state: 284 */ 285 ctx->sample_mask = 0xffff; 286 287 pctx = &ctx->base; 288 pctx->screen = pscreen; 289 pctx->priv = priv; 290 pctx->flush = fd_context_flush; 291 pctx->emit_string_marker = fd_emit_string_marker; 292 pctx->set_debug_callback = fd_set_debug_callback; 293 pctx->create_fence_fd = fd_create_fence_fd; 294 pctx->fence_server_sync = fd_fence_server_sync; 295 pctx->texture_barrier = fd_texture_barrier; 296 297 pctx->stream_uploader = u_upload_create_default(pctx); 298 if (!pctx->stream_uploader) 299 goto fail; 300 pctx->const_uploader = pctx->stream_uploader; 301 302 ctx->batch = fd_bc_alloc_batch(&screen->batch_cache, ctx); 303 304 slab_create_child(&ctx->transfer_pool, &screen->transfer_pool); 305 306 if (!ctx->blit) 307 ctx->blit = fd_blitter_blit; 308 309 fd_draw_init(pctx); 310 fd_resource_context_init(pctx); 311 fd_query_context_init(pctx); 312 fd_texture_init(pctx); 313 fd_state_init(pctx); 314 315 ctx->blitter = util_blitter_create(pctx); 316 if (!ctx->blitter) 317 goto fail; 318 319 ctx->primconvert = util_primconvert_create(pctx, ctx->primtype_mask); 320 if (!ctx->primconvert) 321 goto fail; 322 323 list_inithead(&ctx->hw_active_queries); 324 list_inithead(&ctx->acc_active_queries); 325 326 return pctx; 327 328 fail: 329 pctx->destroy(pctx); 330 return NULL; 331 } 332