Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
 
3
/*
4
 * Copyright (C) 2012 Rob Clark 
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 
27
 */
28
 
29
#include "pipe/p_state.h"
30
#include "util/u_string.h"
31
#include "util/u_memory.h"
32
#include "util/u_inlines.h"
33
#include "util/u_format.h"
34
 
35
#include "freedreno_gmem.h"
36
#include "freedreno_context.h"
37
#include "freedreno_resource.h"
38
#include "freedreno_util.h"
39
 
40
/*
41
 * GMEM is the small (ie. 256KiB for a200, 512KiB for a220, etc) tile buffer
42
 * inside the GPU.  All rendering happens to GMEM.  Larger render targets
43
 * are split into tiles that are small enough for the color (and depth and/or
44
 * stencil, if enabled) buffers to fit within GMEM.  Before rendering a tile,
45
 * if there was not a clear invalidating the previous tile contents, we need
46
 * to restore the previous tiles contents (system mem -> GMEM), and after all
47
 * the draw calls, before moving to the next tile, we need to save the tile
48
 * contents (GMEM -> system mem).
49
 *
50
 * The code in this file handles dealing with GMEM and tiling.
51
 *
52
 * The structure of the ringbuffer ends up being:
53
 *
54
 *     +--<---<-- IB ---<---+---<---+---<---<---<--+
55
 *     |                    |       |              |
56
 *     v                    ^       ^              ^
57
 *   ------------------------------------------------------
58
 *     | clear/draw cmds | Tile0 | Tile1 | .... | TileN |
59
 *   ------------------------------------------------------
60
 *                       ^
61
 *                       |
62
 *                       address submitted in issueibcmds
63
 *
64
 * Where the per-tile section handles scissor setup, mem2gmem restore (if
65
 * needed), IB to draw cmds earlier in the ringbuffer, and then gmem2mem
66
 * resolve.
67
 */
68
 
69
static void
70
calculate_tiles(struct fd_context *ctx)
71
{
72
	struct fd_gmem_stateobj *gmem = &ctx->gmem;
73
	struct pipe_scissor_state *scissor = &ctx->max_scissor;
74
	uint32_t cpp = util_format_get_blocksize(ctx->framebuffer.cbufs[0]->format);
75
	uint32_t gmem_size = ctx->screen->gmemsize_bytes;
76
	uint32_t minx, miny, width, height;
77
	uint32_t nbins_x = 1, nbins_y = 1;
78
	uint32_t bin_w, bin_h;
79
	uint32_t max_width = 992;
80
 
81
	if ((gmem->cpp == cpp) &&
82
			!memcmp(&gmem->scissor, scissor, sizeof(gmem->scissor))) {
83
		/* everything is up-to-date */
84
		return;
85
	}
86
 
87
	minx = scissor->minx & ~31; /* round down to multiple of 32 */
88
	miny = scissor->miny & ~31;
89
	width = scissor->maxx - minx;
90
	height = scissor->maxy - miny;
91
 
92
// TODO we probably could optimize this a bit if we know that
93
// Z or stencil is not enabled for any of the draw calls..
94
//	if (fd_stencil_enabled(ctx->zsa) || fd_depth_enabled(ctx->zsa)) {
95
		gmem_size /= 2;
96
		max_width = 256;
97
//	}
98
 
99
	bin_w = align(width, 32);
100
	bin_h = align(height, 32);
101
 
102
	/* first, find a bin width that satisfies the maximum width
103
	 * restrictions:
104
	 */
105
	while (bin_w > max_width) {
106
		nbins_x++;
107
		bin_w = align(width / nbins_x, 32);
108
	}
109
 
110
	/* then find a bin height that satisfies the memory constraints:
111
	 */
112
	while ((bin_w * bin_h * cpp) > gmem_size) {
113
		nbins_y++;
114
		bin_h = align(height / nbins_y, 32);
115
	}
116
 
117
	DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
118
 
119
	gmem->scissor = *scissor;
120
	gmem->cpp = cpp;
121
	gmem->minx = minx;
122
	gmem->miny = miny;
123
	gmem->bin_h = bin_h;
124
	gmem->bin_w = bin_w;
125
	gmem->nbins_x = nbins_x;
126
	gmem->nbins_y = nbins_y;
127
	gmem->width = width;
128
	gmem->height = height;
129
}
130
 
131
static void
132
render_tiles(struct fd_context *ctx)
133
{
134
	struct fd_gmem_stateobj *gmem = &ctx->gmem;
135
	uint32_t i, yoff = 0;
136
 
137
	yoff= gmem->miny;
138
 
139
	ctx->emit_tile_init(ctx);
140
 
141
	for (i = 0; i < gmem->nbins_y; i++) {
142
		uint32_t j, xoff = gmem->minx;
143
		uint32_t bh = gmem->bin_h;
144
 
145
		/* clip bin height: */
146
		bh = MIN2(bh, gmem->height - yoff);
147
 
148
		for (j = 0; j < gmem->nbins_x; j++) {
149
			uint32_t bw = gmem->bin_w;
150
 
151
			/* clip bin width: */
152
			bw = MIN2(bw, gmem->width - xoff);
153
 
154
			DBG("bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
155
					bh, yoff, bw, xoff);
156
 
157
			ctx->emit_tile_prep(ctx, xoff, yoff, bw, bh);
158
 
159
			if (ctx->restore)
160
				ctx->emit_tile_mem2gmem(ctx, xoff, yoff, bw, bh);
161
 
162
			ctx->emit_tile_renderprep(ctx, xoff, yoff, bw, bh);
163
 
164
			/* emit IB to drawcmds: */
165
			OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
166
 
167
			/* emit gmem2mem to transfer tile back to system memory: */
168
			ctx->emit_tile_gmem2mem(ctx, xoff, yoff, bw, bh);
169
 
170
			xoff += bw;
171
		}
172
 
173
		yoff += bh;
174
	}
175
}
176
 
177
static void
178
render_sysmem(struct fd_context *ctx)
179
{
180
	ctx->emit_sysmem_prep(ctx);
181
 
182
	/* emit IB to drawcmds: */
183
	OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
184
}
185
 
186
void
187
fd_gmem_render_tiles(struct pipe_context *pctx)
188
{
189
	struct fd_context *ctx = fd_context(pctx);
190
	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
191
	uint32_t timestamp = 0;
192
	bool sysmem = false;
193
 
194
	if (ctx->emit_sysmem_prep) {
195
		if (ctx->cleared || ctx->gmem_reason || (ctx->num_draws > 5)) {
196
			DBG("GMEM: cleared=%x, gmem_reason=%x, num_draws=%u",
197
				ctx->cleared, ctx->gmem_reason, ctx->num_draws);
198
		} else {
199
			sysmem = true;
200
		}
201
	}
202
 
203
	/* mark the end of the clear/draw cmds before emitting per-tile cmds: */
204
	fd_ringmarker_mark(ctx->draw_end);
205
 
206
	if (sysmem) {
207
		DBG("rendering sysmem (%s/%s)",
208
			util_format_name(pfb->cbufs[0]->format),
209
			pfb->zsbuf ? util_format_name(pfb->zsbuf->format) : "none");
210
		render_sysmem(ctx);
211
	} else {
212
		struct fd_gmem_stateobj *gmem = &ctx->gmem;
213
		DBG("rendering %dx%d tiles (%s/%s)", gmem->nbins_x, gmem->nbins_y,
214
			util_format_name(pfb->cbufs[0]->format),
215
			pfb->zsbuf ? util_format_name(pfb->zsbuf->format) : "none");
216
		calculate_tiles(ctx);
217
		render_tiles(ctx);
218
	}
219
 
220
	/* GPU executes starting from tile cmds, which IB back to draw cmds: */
221
	fd_ringmarker_flush(ctx->draw_end);
222
 
223
	/* mark start for next draw cmds: */
224
	fd_ringmarker_mark(ctx->draw_start);
225
 
226
	/* update timestamps on render targets: */
227
	timestamp = fd_ringbuffer_timestamp(ctx->ring);
228
	fd_resource(pfb->cbufs[0]->texture)->timestamp = timestamp;
229
	if (pfb->zsbuf)
230
		fd_resource(pfb->zsbuf->texture)->timestamp = timestamp;
231
 
232
	/* reset maximal bounds: */
233
	ctx->max_scissor.minx = ctx->max_scissor.miny = ~0;
234
	ctx->max_scissor.maxx = ctx->max_scissor.maxy = 0;
235
 
236
	/* Note that because the per-tile setup and mem2gmem/gmem2mem are emitted
237
	 * after the draw/clear calls, but executed before, we need to preemptively
238
	 * flag some state as dirty before the first draw/clear call.
239
	 *
240
	 * TODO maybe we need to mark all state as dirty to not worry about state
241
	 * being clobbered by other contexts?
242
	 */
243
	ctx->dirty |= FD_DIRTY_ZSA |
244
			FD_DIRTY_RASTERIZER |
245
			FD_DIRTY_FRAMEBUFFER |
246
			FD_DIRTY_SAMPLE_MASK |
247
			FD_DIRTY_VIEWPORT |
248
			FD_DIRTY_CONSTBUF |
249
			FD_DIRTY_PROG |
250
			FD_DIRTY_SCISSOR |
251
			/* probably only needed if we need to mem2gmem on the next
252
			 * draw..  but not sure if there is a good way to know?
253
			 */
254
			FD_DIRTY_VERTTEX |
255
			FD_DIRTY_FRAGTEX |
256
			FD_DIRTY_BLEND;
257
 
258
	if (fd_mesa_debug & FD_DBG_DGMEM)
259
		ctx->dirty = 0xffffffff;
260
}