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_draw.h" 31 #include "freedreno_fence.h" 32 #include "freedreno_program.h" 33 #include "freedreno_resource.h" 34 #include "freedreno_texture.h" 35 #include "freedreno_state.h" 36 #include "freedreno_gmem.h" 37 #include "freedreno_query.h" 38 #include "freedreno_query_hw.h" 39 #include "freedreno_util.h" 40 41 static void 42 fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, 43 unsigned flags) 44 { 45 struct fd_context *ctx = fd_context(pctx); 46 47 if (flags & PIPE_FLUSH_FENCE_FD) 48 ctx->batch->needs_out_fence_fd = true; 49 50 if (!ctx->screen->reorder) { 51 fd_batch_flush(ctx->batch, true); 52 } else { 53 fd_bc_flush(&ctx->screen->batch_cache, ctx); 54 } 55 56 if (fence) { 57 /* if there hasn't been any rendering submitted yet, we might not 58 * have actually created a fence 59 */ 60 if (!ctx->last_fence || ctx->batch->needs_out_fence_fd) { 61 ctx->batch->needs_flush = true; 62 fd_gmem_render_noop(ctx->batch); 63 fd_batch_reset(ctx->batch); 64 } 65 fd_fence_ref(pctx->screen, fence, ctx->last_fence); 66 } 67 } 68 69 /** 70 * emit marker string as payload of a no-op packet, which can be 71 * decoded by cffdump. 72 */ 73 static void 74 fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len) 75 { 76 struct fd_context *ctx = fd_context(pctx); 77 struct fd_ringbuffer *ring; 78 const uint32_t *buf = (const void *)string; 79 80 if (!ctx->batch) 81 return; 82 83 ring = ctx->batch->draw; 84 85 /* max packet size is 0x3fff dwords: */ 86 len = MIN2(len, 0x3fff * 4); 87 88 if (ctx->screen->gpu_id >= 500) 89 OUT_PKT7(ring, CP_NOP, align(len, 4) / 4); 90 else 91 OUT_PKT3(ring, CP_NOP, align(len, 4) / 4); 92 while (len >= 4) { 93 OUT_RING(ring, *buf); 94 buf++; 95 len -= 4; 96 } 97 98 /* copy remainder bytes without reading past end of input string: */ 99 if (len > 0) { 100 uint32_t w = 0; 101 memcpy(&w, buf, len); 102 OUT_RING(ring, w); 103 } 104 } 105 106 void 107 fd_context_destroy(struct pipe_context *pctx) 108 { 109 struct fd_context *ctx = fd_context(pctx); 110 unsigned i; 111 112 DBG(""); 113 114 if (ctx->screen->reorder) 115 util_queue_destroy(&ctx->flush_queue); 116 117 fd_batch_reference(&ctx->batch, NULL); /* unref current batch */ 118 fd_bc_invalidate_context(ctx); 119 120 fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); 121 122 fd_prog_fini(pctx); 123 fd_hw_query_fini(pctx); 124 125 if (ctx->blitter) 126 util_blitter_destroy(ctx->blitter); 127 128 if (ctx->clear_rs_state) 129 pctx->delete_rasterizer_state(pctx, ctx->clear_rs_state); 130 131 if (ctx->primconvert) 132 util_primconvert_destroy(ctx->primconvert); 133 134 slab_destroy_child(&ctx->transfer_pool); 135 136 for (i = 0; i < ARRAY_SIZE(ctx->pipe); i++) { 137 struct fd_vsc_pipe *pipe = &ctx->pipe[i]; 138 if (!pipe->bo) 139 break; 140 fd_bo_del(pipe->bo); 141 } 142 143 fd_device_del(ctx->dev); 144 145 if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) { 146 printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_restore=%u\n", 147 (uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem, 148 (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_restore); 149 } 150 151 FREE(ctx); 152 } 153 154 static void 155 fd_set_debug_callback(struct pipe_context *pctx, 156 const struct pipe_debug_callback *cb) 157 { 158 struct fd_context *ctx = fd_context(pctx); 159 160 if (cb) 161 ctx->debug = *cb; 162 else 163 memset(&ctx->debug, 0, sizeof(ctx->debug)); 164 } 165 166 /* TODO we could combine a few of these small buffers (solid_vbuf, 167 * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and 168 * save a tiny bit of memory 169 */ 170 171 static struct pipe_resource * 172 create_solid_vertexbuf(struct pipe_context *pctx) 173 { 174 static const float init_shader_const[] = { 175 -1.000000, +1.000000, +1.000000, 176 +1.000000, -1.000000, +1.000000, 177 }; 178 struct pipe_resource *prsc = pipe_buffer_create(pctx->screen, 179 PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(init_shader_const)); 180 pipe_buffer_write(pctx, prsc, 0, 181 sizeof(init_shader_const), init_shader_const); 182 return prsc; 183 } 184 185 static struct pipe_resource * 186 create_blit_texcoord_vertexbuf(struct pipe_context *pctx) 187 { 188 struct pipe_resource *prsc = pipe_buffer_create(pctx->screen, 189 PIPE_BIND_CUSTOM, PIPE_USAGE_DYNAMIC, 16); 190 return prsc; 191 } 192 193 void 194 fd_context_setup_common_vbos(struct fd_context *ctx) 195 { 196 struct pipe_context *pctx = &ctx->base; 197 198 ctx->solid_vbuf = create_solid_vertexbuf(pctx); 199 ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx); 200 201 /* setup solid_vbuf_state: */ 202 ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state( 203 pctx, 1, (struct pipe_vertex_element[]){{ 204 .vertex_buffer_index = 0, 205 .src_offset = 0, 206 .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 207 }}); 208 ctx->solid_vbuf_state.vertexbuf.count = 1; 209 ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12; 210 ctx->solid_vbuf_state.vertexbuf.vb[0].buffer = ctx->solid_vbuf; 211 212 /* setup blit_vbuf_state: */ 213 ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state( 214 pctx, 2, (struct pipe_vertex_element[]){{ 215 .vertex_buffer_index = 0, 216 .src_offset = 0, 217 .src_format = PIPE_FORMAT_R32G32_FLOAT, 218 }, { 219 .vertex_buffer_index = 1, 220 .src_offset = 0, 221 .src_format = PIPE_FORMAT_R32G32B32_FLOAT, 222 }}); 223 ctx->blit_vbuf_state.vertexbuf.count = 2; 224 ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8; 225 ctx->blit_vbuf_state.vertexbuf.vb[0].buffer = ctx->blit_texcoord_vbuf; 226 ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12; 227 ctx->blit_vbuf_state.vertexbuf.vb[1].buffer = ctx->solid_vbuf; 228 } 229 230 void 231 fd_context_cleanup_common_vbos(struct fd_context *ctx) 232 { 233 struct pipe_context *pctx = &ctx->base; 234 235 pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx); 236 pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx); 237 238 pipe_resource_reference(&ctx->solid_vbuf, NULL); 239 pipe_resource_reference(&ctx->blit_texcoord_vbuf, NULL); 240 } 241 242 struct pipe_context * 243 fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, 244 const uint8_t *primtypes, void *priv) 245 { 246 struct fd_screen *screen = fd_screen(pscreen); 247 struct pipe_context *pctx; 248 int i; 249 250 ctx->screen = screen; 251 252 ctx->primtypes = primtypes; 253 ctx->primtype_mask = 0; 254 for (i = 0; i < PIPE_PRIM_MAX; i++) 255 if (primtypes[i]) 256 ctx->primtype_mask |= (1 << i); 257 258 /* need some sane default in case state tracker doesn't 259 * set some state: 260 */ 261 ctx->sample_mask = 0xffff; 262 263 pctx = &ctx->base; 264 pctx->screen = pscreen; 265 pctx->priv = priv; 266 pctx->flush = fd_context_flush; 267 pctx->emit_string_marker = fd_emit_string_marker; 268 pctx->set_debug_callback = fd_set_debug_callback; 269 pctx->create_fence_fd = fd_create_fence_fd; 270 pctx->fence_server_sync = fd_fence_server_sync; 271 272 /* TODO what about compute? Ideally it creates it's own independent 273 * batches per compute job (since it isn't using tiling, so no point 274 * in getting involved with the re-ordering madness).. 275 */ 276 if (!screen->reorder) { 277 ctx->batch = fd_bc_alloc_batch(&screen->batch_cache, ctx); 278 } 279 280 slab_create_child(&ctx->transfer_pool, &screen->transfer_pool); 281 282 fd_draw_init(pctx); 283 fd_resource_context_init(pctx); 284 fd_query_context_init(pctx); 285 fd_texture_init(pctx); 286 fd_state_init(pctx); 287 fd_hw_query_init(pctx); 288 289 ctx->blitter = util_blitter_create(pctx); 290 if (!ctx->blitter) 291 goto fail; 292 293 ctx->primconvert = util_primconvert_create(pctx, ctx->primtype_mask); 294 if (!ctx->primconvert) 295 goto fail; 296 297 return pctx; 298 299 fail: 300 pctx->destroy(pctx); 301 return NULL; 302 } 303