1848b8605Smrg/*
2848b8605Smrg * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice (including the next
12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
13848b8605Smrg * Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21848b8605Smrg * SOFTWARE.
22848b8605Smrg *
23848b8605Smrg * Authors:
24848b8605Smrg *    Rob Clark <robclark@freedesktop.org>
25848b8605Smrg */
26848b8605Smrg
27848b8605Smrg#include "freedreno_context.h"
28b8e80941Smrg#include "freedreno_blitter.h"
29848b8605Smrg#include "freedreno_draw.h"
30b8e80941Smrg#include "freedreno_fence.h"
31848b8605Smrg#include "freedreno_program.h"
32848b8605Smrg#include "freedreno_resource.h"
33848b8605Smrg#include "freedreno_texture.h"
34848b8605Smrg#include "freedreno_state.h"
35848b8605Smrg#include "freedreno_gmem.h"
36848b8605Smrg#include "freedreno_query.h"
37848b8605Smrg#include "freedreno_query_hw.h"
38848b8605Smrg#include "freedreno_util.h"
39b8e80941Smrg#include "util/u_upload_mgr.h"
40848b8605Smrg
41b8e80941Smrgstatic void
42b8e80941Smrgfd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep,
43b8e80941Smrg		unsigned flags)
44848b8605Smrg{
45b8e80941Smrg	struct fd_context *ctx = fd_context(pctx);
46b8e80941Smrg	struct pipe_fence_handle *fence = NULL;
47b8e80941Smrg	// TODO we want to lookup batch if it exists, but not create one if not.
48b8e80941Smrg	struct fd_batch *batch = fd_context_batch(ctx);
49848b8605Smrg
50b8e80941Smrg	DBG("%p: flush: flags=%x\n", ctx->batch, flags);
51848b8605Smrg
52b8e80941Smrg	/* if no rendering since last flush, ie. app just decided it needed
53b8e80941Smrg	 * a fence, re-use the last one:
54b8e80941Smrg	 */
55b8e80941Smrg	if (ctx->last_fence) {
56b8e80941Smrg		fd_fence_ref(pctx->screen, &fence, ctx->last_fence);
57b8e80941Smrg		goto out;
58848b8605Smrg	}
59848b8605Smrg
60b8e80941Smrg	if (!batch)
61b8e80941Smrg		return;
62848b8605Smrg
63b8e80941Smrg	/* Take a ref to the batch's fence (batch can be unref'd when flushed: */
64b8e80941Smrg	fd_fence_ref(pctx->screen, &fence, batch->fence);
65848b8605Smrg
66b8e80941Smrg	/* TODO is it worth trying to figure out if app is using fence-fd's, to
67b8e80941Smrg	 * avoid requesting one every batch?
68b8e80941Smrg	 */
69b8e80941Smrg	batch->needs_out_fence_fd = true;
70b8e80941Smrg
71b8e80941Smrg	if (!ctx->screen->reorder) {
72b8e80941Smrg		fd_batch_flush(batch, true, false);
73b8e80941Smrg	} else if (flags & PIPE_FLUSH_DEFERRED) {
74b8e80941Smrg		fd_bc_flush_deferred(&ctx->screen->batch_cache, ctx);
75b8e80941Smrg	} else {
76b8e80941Smrg		fd_bc_flush(&ctx->screen->batch_cache, ctx);
77b8e80941Smrg	}
78848b8605Smrg
79b8e80941Smrgout:
80b8e80941Smrg	if (fencep)
81b8e80941Smrg		fd_fence_ref(pctx->screen, fencep, fence);
82848b8605Smrg
83b8e80941Smrg	fd_fence_ref(pctx->screen, &ctx->last_fence, fence);
84848b8605Smrg
85b8e80941Smrg	fd_fence_ref(pctx->screen, &fence, NULL);
86b8e80941Smrg}
87848b8605Smrg
88b8e80941Smrgstatic void
89b8e80941Smrgfd_texture_barrier(struct pipe_context *pctx, unsigned flags)
90b8e80941Smrg{
91b8e80941Smrg	if (flags == PIPE_TEXTURE_BARRIER_FRAMEBUFFER) {
92b8e80941Smrg		struct fd_context *ctx = fd_context(pctx);
93848b8605Smrg
94b8e80941Smrg		if (ctx->framebuffer_barrier) {
95b8e80941Smrg			ctx->framebuffer_barrier(ctx);
96b8e80941Smrg			return;
97b8e80941Smrg		}
98b8e80941Smrg	}
99848b8605Smrg
100b8e80941Smrg	/* On devices that could sample from GMEM we could possibly do better.
101b8e80941Smrg	 * Or if we knew that we were doing GMEM bypass we could just emit a
102b8e80941Smrg	 * cache flush, perhaps?  But we don't know if future draws would cause
103b8e80941Smrg	 * us to use GMEM, and a flush in bypass isn't the end of the world.
104b8e80941Smrg	 */
105b8e80941Smrg	fd_context_flush(pctx, NULL, 0);
106b8e80941Smrg}
107848b8605Smrg
108b8e80941Smrgstatic void
109b8e80941Smrgfd_memory_barrier(struct pipe_context *pctx, unsigned flags)
110b8e80941Smrg{
111b8e80941Smrg	if (!(flags & ~PIPE_BARRIER_UPDATE))
112b8e80941Smrg		return;
113848b8605Smrg
114b8e80941Smrg	fd_context_flush(pctx, NULL, 0);
115b8e80941Smrg	/* TODO do we need to check for persistently mapped buffers and fd_bo_cpu_prep()?? */
116848b8605Smrg}
117848b8605Smrg
118b8e80941Smrg/**
119b8e80941Smrg * emit marker string as payload of a no-op packet, which can be
120b8e80941Smrg * decoded by cffdump.
121848b8605Smrg */
122b8e80941Smrgstatic void
123b8e80941Smrgfd_emit_string_marker(struct pipe_context *pctx, const char *string, int len)
124848b8605Smrg{
125848b8605Smrg	struct fd_context *ctx = fd_context(pctx);
126b8e80941Smrg	struct fd_ringbuffer *ring;
127b8e80941Smrg	const uint32_t *buf = (const void *)string;
128848b8605Smrg
129b8e80941Smrg	if (!ctx->batch)
130848b8605Smrg		return;
131848b8605Smrg
132b8e80941Smrg	ctx->batch->needs_flush = true;
133848b8605Smrg
134b8e80941Smrg	ring = ctx->batch->draw;
135848b8605Smrg
136b8e80941Smrg	/* max packet size is 0x3fff dwords: */
137b8e80941Smrg	len = MIN2(len, 0x3fff * 4);
138848b8605Smrg
139b8e80941Smrg	if (ctx->screen->gpu_id >= 500)
140b8e80941Smrg		OUT_PKT7(ring, CP_NOP, align(len, 4) / 4);
141b8e80941Smrg	else
142b8e80941Smrg		OUT_PKT3(ring, CP_NOP, align(len, 4) / 4);
143b8e80941Smrg	while (len >= 4) {
144b8e80941Smrg		OUT_RING(ring, *buf);
145b8e80941Smrg		buf++;
146b8e80941Smrg		len -= 4;
147848b8605Smrg	}
148848b8605Smrg
149b8e80941Smrg	/* copy remainder bytes without reading past end of input string: */
150b8e80941Smrg	if (len > 0) {
151b8e80941Smrg		uint32_t w = 0;
152b8e80941Smrg		memcpy(&w, buf, len);
153b8e80941Smrg		OUT_RING(ring, w);
154b8e80941Smrg	}
155848b8605Smrg}
156848b8605Smrg
157848b8605Smrgvoid
158848b8605Smrgfd_context_destroy(struct pipe_context *pctx)
159848b8605Smrg{
160848b8605Smrg	struct fd_context *ctx = fd_context(pctx);
161848b8605Smrg	unsigned i;
162848b8605Smrg
163848b8605Smrg	DBG("");
164848b8605Smrg
165b8e80941Smrg	fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
166b8e80941Smrg
167b8e80941Smrg	if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue))
168b8e80941Smrg		util_queue_destroy(&ctx->flush_queue);
169848b8605Smrg
170b8e80941Smrg	util_copy_framebuffer_state(&ctx->framebuffer, NULL);
171b8e80941Smrg	fd_batch_reference(&ctx->batch, NULL);  /* unref current batch */
172b8e80941Smrg	fd_bc_invalidate_context(ctx);
173b8e80941Smrg
174b8e80941Smrg	fd_prog_fini(pctx);
175848b8605Smrg
176848b8605Smrg	if (ctx->blitter)
177848b8605Smrg		util_blitter_destroy(ctx->blitter);
178848b8605Smrg
179b8e80941Smrg	if (pctx->stream_uploader)
180b8e80941Smrg		u_upload_destroy(pctx->stream_uploader);
181848b8605Smrg
182b8e80941Smrg	if (ctx->clear_rs_state)
183b8e80941Smrg		pctx->delete_rasterizer_state(pctx, ctx->clear_rs_state);
184848b8605Smrg
185b8e80941Smrg	if (ctx->primconvert)
186b8e80941Smrg		util_primconvert_destroy(ctx->primconvert);
187848b8605Smrg
188b8e80941Smrg	slab_destroy_child(&ctx->transfer_pool);
189848b8605Smrg
190b8e80941Smrg	for (i = 0; i < ARRAY_SIZE(ctx->vsc_pipe); i++) {
191b8e80941Smrg		struct fd_vsc_pipe *pipe = &ctx->vsc_pipe[i];
192848b8605Smrg		if (!pipe->bo)
193848b8605Smrg			break;
194848b8605Smrg		fd_bo_del(pipe->bo);
195848b8605Smrg	}
196848b8605Smrg
197848b8605Smrg	fd_device_del(ctx->dev);
198b8e80941Smrg	fd_pipe_del(ctx->pipe);
199848b8605Smrg
200b8e80941Smrg	if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) {
201b8e80941Smrg		printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, batch_restore=%u\n",
202b8e80941Smrg			(uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem,
203b8e80941Smrg			(uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_nondraw,
204b8e80941Smrg			(uint32_t)ctx->stats.batch_restore);
205b8e80941Smrg	}
206b8e80941Smrg}
207b8e80941Smrg
208b8e80941Smrgstatic void
209b8e80941Smrgfd_set_debug_callback(struct pipe_context *pctx,
210b8e80941Smrg		const struct pipe_debug_callback *cb)
211b8e80941Smrg{
212b8e80941Smrg	struct fd_context *ctx = fd_context(pctx);
213b8e80941Smrg
214b8e80941Smrg	if (cb)
215b8e80941Smrg		ctx->debug = *cb;
216b8e80941Smrg	else
217b8e80941Smrg		memset(&ctx->debug, 0, sizeof(ctx->debug));
218b8e80941Smrg}
219b8e80941Smrg
220b8e80941Smrgstatic uint32_t
221b8e80941Smrgfd_get_reset_count(struct fd_context *ctx, bool per_context)
222b8e80941Smrg{
223b8e80941Smrg	uint64_t val;
224b8e80941Smrg	enum fd_param_id param =
225b8e80941Smrg		per_context ? FD_CTX_FAULTS : FD_GLOBAL_FAULTS;
226b8e80941Smrg	int ret = fd_pipe_get_param(ctx->pipe, param, &val);
227b8e80941Smrg	debug_assert(!ret);
228b8e80941Smrg	return val;
229b8e80941Smrg}
230b8e80941Smrg
231b8e80941Smrgstatic enum pipe_reset_status
232b8e80941Smrgfd_get_device_reset_status(struct pipe_context *pctx)
233b8e80941Smrg{
234b8e80941Smrg	struct fd_context *ctx = fd_context(pctx);
235b8e80941Smrg	int context_faults = fd_get_reset_count(ctx, true);
236b8e80941Smrg	int global_faults  = fd_get_reset_count(ctx, false);
237b8e80941Smrg	enum pipe_reset_status status;
238b8e80941Smrg
239b8e80941Smrg	if (context_faults != ctx->context_reset_count) {
240b8e80941Smrg		status = PIPE_GUILTY_CONTEXT_RESET;
241b8e80941Smrg	} else if (global_faults != ctx->global_reset_count) {
242b8e80941Smrg		status = PIPE_INNOCENT_CONTEXT_RESET;
243b8e80941Smrg	} else {
244b8e80941Smrg		status = PIPE_NO_RESET;
245b8e80941Smrg	}
246b8e80941Smrg
247b8e80941Smrg	ctx->context_reset_count = context_faults;
248b8e80941Smrg	ctx->global_reset_count = global_faults;
249b8e80941Smrg
250b8e80941Smrg	return status;
251b8e80941Smrg}
252b8e80941Smrg
253b8e80941Smrg/* TODO we could combine a few of these small buffers (solid_vbuf,
254b8e80941Smrg * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and
255b8e80941Smrg * save a tiny bit of memory
256b8e80941Smrg */
257b8e80941Smrg
258b8e80941Smrgstatic struct pipe_resource *
259b8e80941Smrgcreate_solid_vertexbuf(struct pipe_context *pctx)
260b8e80941Smrg{
261b8e80941Smrg	static const float init_shader_const[] = {
262b8e80941Smrg			-1.000000, +1.000000, +1.000000,
263b8e80941Smrg			+1.000000, -1.000000, +1.000000,
264b8e80941Smrg	};
265b8e80941Smrg	struct pipe_resource *prsc = pipe_buffer_create(pctx->screen,
266b8e80941Smrg			PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(init_shader_const));
267b8e80941Smrg	pipe_buffer_write(pctx, prsc, 0,
268b8e80941Smrg			sizeof(init_shader_const), init_shader_const);
269b8e80941Smrg	return prsc;
270b8e80941Smrg}
271b8e80941Smrg
272b8e80941Smrgstatic struct pipe_resource *
273b8e80941Smrgcreate_blit_texcoord_vertexbuf(struct pipe_context *pctx)
274b8e80941Smrg{
275b8e80941Smrg	struct pipe_resource *prsc = pipe_buffer_create(pctx->screen,
276b8e80941Smrg			PIPE_BIND_CUSTOM, PIPE_USAGE_DYNAMIC, 16);
277b8e80941Smrg	return prsc;
278b8e80941Smrg}
279b8e80941Smrg
280b8e80941Smrgvoid
281b8e80941Smrgfd_context_setup_common_vbos(struct fd_context *ctx)
282b8e80941Smrg{
283b8e80941Smrg	struct pipe_context *pctx = &ctx->base;
284b8e80941Smrg
285b8e80941Smrg	ctx->solid_vbuf = create_solid_vertexbuf(pctx);
286b8e80941Smrg	ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx);
287b8e80941Smrg
288b8e80941Smrg	/* setup solid_vbuf_state: */
289b8e80941Smrg	ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state(
290b8e80941Smrg			pctx, 1, (struct pipe_vertex_element[]){{
291b8e80941Smrg				.vertex_buffer_index = 0,
292b8e80941Smrg				.src_offset = 0,
293b8e80941Smrg				.src_format = PIPE_FORMAT_R32G32B32_FLOAT,
294b8e80941Smrg			}});
295b8e80941Smrg	ctx->solid_vbuf_state.vertexbuf.count = 1;
296b8e80941Smrg	ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12;
297b8e80941Smrg	ctx->solid_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->solid_vbuf;
298b8e80941Smrg
299b8e80941Smrg	/* setup blit_vbuf_state: */
300b8e80941Smrg	ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state(
301b8e80941Smrg			pctx, 2, (struct pipe_vertex_element[]){{
302b8e80941Smrg				.vertex_buffer_index = 0,
303b8e80941Smrg				.src_offset = 0,
304b8e80941Smrg				.src_format = PIPE_FORMAT_R32G32_FLOAT,
305b8e80941Smrg			}, {
306b8e80941Smrg				.vertex_buffer_index = 1,
307b8e80941Smrg				.src_offset = 0,
308b8e80941Smrg				.src_format = PIPE_FORMAT_R32G32B32_FLOAT,
309b8e80941Smrg			}});
310b8e80941Smrg	ctx->blit_vbuf_state.vertexbuf.count = 2;
311b8e80941Smrg	ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8;
312b8e80941Smrg	ctx->blit_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->blit_texcoord_vbuf;
313b8e80941Smrg	ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12;
314b8e80941Smrg	ctx->blit_vbuf_state.vertexbuf.vb[1].buffer.resource = ctx->solid_vbuf;
315b8e80941Smrg}
316b8e80941Smrg
317b8e80941Smrgvoid
318b8e80941Smrgfd_context_cleanup_common_vbos(struct fd_context *ctx)
319b8e80941Smrg{
320b8e80941Smrg	struct pipe_context *pctx = &ctx->base;
321b8e80941Smrg
322b8e80941Smrg	pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx);
323b8e80941Smrg	pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx);
324b8e80941Smrg
325b8e80941Smrg	pipe_resource_reference(&ctx->solid_vbuf, NULL);
326b8e80941Smrg	pipe_resource_reference(&ctx->blit_texcoord_vbuf, NULL);
327848b8605Smrg}
328848b8605Smrg
329848b8605Smrgstruct pipe_context *
330848b8605Smrgfd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen,
331b8e80941Smrg		const uint8_t *primtypes, void *priv, unsigned flags)
332848b8605Smrg{
333848b8605Smrg	struct fd_screen *screen = fd_screen(pscreen);
334848b8605Smrg	struct pipe_context *pctx;
335b8e80941Smrg	unsigned prio = 1;
336848b8605Smrg	int i;
337848b8605Smrg
338b8e80941Smrg	/* lower numerical value == higher priority: */
339b8e80941Smrg	if (fd_mesa_debug & FD_DBG_HIPRIO)
340b8e80941Smrg		prio = 0;
341b8e80941Smrg	else if (flags & PIPE_CONTEXT_HIGH_PRIORITY)
342b8e80941Smrg		prio = 0;
343b8e80941Smrg	else if (flags & PIPE_CONTEXT_LOW_PRIORITY)
344b8e80941Smrg		prio = 2;
345b8e80941Smrg
346848b8605Smrg	ctx->screen = screen;
347b8e80941Smrg	ctx->pipe = fd_pipe_new2(screen->dev, FD_PIPE_3D, prio);
348b8e80941Smrg
349b8e80941Smrg	if (fd_device_version(screen->dev) >= FD_VERSION_ROBUSTNESS) {
350b8e80941Smrg		ctx->context_reset_count = fd_get_reset_count(ctx, true);
351b8e80941Smrg		ctx->global_reset_count = fd_get_reset_count(ctx, false);
352b8e80941Smrg	}
353848b8605Smrg
354848b8605Smrg	ctx->primtypes = primtypes;
355848b8605Smrg	ctx->primtype_mask = 0;
356848b8605Smrg	for (i = 0; i < PIPE_PRIM_MAX; i++)
357848b8605Smrg		if (primtypes[i])
358848b8605Smrg			ctx->primtype_mask |= (1 << i);
359848b8605Smrg
360848b8605Smrg	/* need some sane default in case state tracker doesn't
361848b8605Smrg	 * set some state:
362848b8605Smrg	 */
363848b8605Smrg	ctx->sample_mask = 0xffff;
364848b8605Smrg
365848b8605Smrg	pctx = &ctx->base;
366848b8605Smrg	pctx->screen = pscreen;
367848b8605Smrg	pctx->priv = priv;
368848b8605Smrg	pctx->flush = fd_context_flush;
369b8e80941Smrg	pctx->emit_string_marker = fd_emit_string_marker;
370b8e80941Smrg	pctx->set_debug_callback = fd_set_debug_callback;
371b8e80941Smrg	pctx->get_device_reset_status = fd_get_device_reset_status;
372b8e80941Smrg	pctx->create_fence_fd = fd_create_fence_fd;
373b8e80941Smrg	pctx->fence_server_sync = fd_fence_server_sync;
374b8e80941Smrg	pctx->texture_barrier = fd_texture_barrier;
375b8e80941Smrg	pctx->memory_barrier = fd_memory_barrier;
376b8e80941Smrg
377b8e80941Smrg	pctx->stream_uploader = u_upload_create_default(pctx);
378b8e80941Smrg	if (!pctx->stream_uploader)
379b8e80941Smrg		goto fail;
380b8e80941Smrg	pctx->const_uploader = pctx->stream_uploader;
381848b8605Smrg
382b8e80941Smrg	if (!ctx->screen->reorder)
383b8e80941Smrg		ctx->batch = fd_bc_alloc_batch(&screen->batch_cache, ctx, false);
384848b8605Smrg
385b8e80941Smrg	slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);
386848b8605Smrg
387848b8605Smrg	fd_draw_init(pctx);
388848b8605Smrg	fd_resource_context_init(pctx);
389848b8605Smrg	fd_query_context_init(pctx);
390848b8605Smrg	fd_texture_init(pctx);
391848b8605Smrg	fd_state_init(pctx);
392848b8605Smrg
393848b8605Smrg	ctx->blitter = util_blitter_create(pctx);
394848b8605Smrg	if (!ctx->blitter)
395848b8605Smrg		goto fail;
396848b8605Smrg
397848b8605Smrg	ctx->primconvert = util_primconvert_create(pctx, ctx->primtype_mask);
398848b8605Smrg	if (!ctx->primconvert)
399848b8605Smrg		goto fail;
400848b8605Smrg
401b8e80941Smrg	list_inithead(&ctx->hw_active_queries);
402b8e80941Smrg	list_inithead(&ctx->acc_active_queries);
403b8e80941Smrg
404848b8605Smrg	return pctx;
405848b8605Smrg
406848b8605Smrgfail:
407848b8605Smrg	pctx->destroy(pctx);
408848b8605Smrg	return NULL;
409848b8605Smrg}
410