142542f5fSchristos/*
242542f5fSchristos * Copyright © 2012 Intel Corporation
342542f5fSchristos *
442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
542542f5fSchristos * copy of this software and associated documentation files (the "Software"),
642542f5fSchristos * to deal in the Software without restriction, including without limitation
742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
942542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1042542f5fSchristos *
1142542f5fSchristos * The above copyright notice and this permission notice (including the next
1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1342542f5fSchristos * Software.
1442542f5fSchristos *
1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2142542f5fSchristos * SOFTWARE.
2242542f5fSchristos *
2342542f5fSchristos * Authors:
2442542f5fSchristos *    Chris Wilson <chris@chris-wilson.co.uk>
2542542f5fSchristos *
2642542f5fSchristos */
2742542f5fSchristos
2842542f5fSchristos#ifdef HAVE_CONFIG_H
2942542f5fSchristos#include "config.h"
3042542f5fSchristos#endif
3142542f5fSchristos
3242542f5fSchristos#include "sna.h"
3342542f5fSchristos#include "sna_render.h"
3442542f5fSchristos#include "sna_render_inline.h"
3542542f5fSchristos#include "gen8_vertex.h"
3642542f5fSchristos
3742542f5fSchristosvoid gen8_vertex_align(struct sna *sna, const struct sna_composite_op *op)
3842542f5fSchristos{
3942542f5fSchristos	int vertex_index;
4042542f5fSchristos
4142542f5fSchristos	assert(op->floats_per_rect == 3*op->floats_per_vertex);
4242542f5fSchristos
4342542f5fSchristos	vertex_index = (sna->render.vertex_used + op->floats_per_vertex - 1) / op->floats_per_vertex;
4442542f5fSchristos	if ((int)sna->render.vertex_size - vertex_index * op->floats_per_vertex < 2*op->floats_per_rect) {
4542542f5fSchristos		DBG(("%s: flushing vertex buffer: new index=%d, max=%d\n",
4642542f5fSchristos		     __FUNCTION__, vertex_index, sna->render.vertex_size / op->floats_per_vertex));
4742542f5fSchristos		if (gen8_vertex_finish(sna) < 2*op->floats_per_rect) {
4842542f5fSchristos			kgem_submit(&sna->kgem);
4942542f5fSchristos			_kgem_set_mode(&sna->kgem, KGEM_RENDER);
5042542f5fSchristos		}
5142542f5fSchristos
5242542f5fSchristos		vertex_index = (sna->render.vertex_used + op->floats_per_vertex - 1) / op->floats_per_vertex;
5342542f5fSchristos		assert(vertex_index * op->floats_per_vertex <= sna->render.vertex_size);
5442542f5fSchristos	}
5542542f5fSchristos
5642542f5fSchristos	sna->render.vertex_index = vertex_index;
5742542f5fSchristos	sna->render.vertex_used = vertex_index * op->floats_per_vertex;
5842542f5fSchristos}
5942542f5fSchristos
6042542f5fSchristosvoid gen8_vertex_flush(struct sna *sna)
6142542f5fSchristos{
6242542f5fSchristos	DBG(("%s[%x] = %d\n", __FUNCTION__,
6342542f5fSchristos	     4*sna->render.vertex_offset,
6442542f5fSchristos	     sna->render.vertex_index - sna->render.vertex_start));
6542542f5fSchristos
6642542f5fSchristos	assert(sna->render.vertex_offset);
6742542f5fSchristos	assert(sna->render.vertex_offset <= sna->kgem.nbatch);
6842542f5fSchristos	assert(sna->render.vertex_index > sna->render.vertex_start);
6942542f5fSchristos	assert(sna->render.vertex_used <= sna->render.vertex_size);
7042542f5fSchristos
7142542f5fSchristos	sna->kgem.batch[sna->render.vertex_offset] =
7242542f5fSchristos		sna->render.vertex_index - sna->render.vertex_start;
7342542f5fSchristos	sna->render.vertex_offset = 0;
7442542f5fSchristos}
7542542f5fSchristos
7642542f5fSchristosint gen8_vertex_finish(struct sna *sna)
7742542f5fSchristos{
7842542f5fSchristos	struct kgem_bo *bo;
7942542f5fSchristos	unsigned int i;
8042542f5fSchristos	unsigned hint, size;
8142542f5fSchristos
8242542f5fSchristos	DBG(("%s: used=%d / %d\n", __FUNCTION__,
8342542f5fSchristos	     sna->render.vertex_used, sna->render.vertex_size));
8442542f5fSchristos	assert(sna->render.vertex_offset == 0);
8542542f5fSchristos	assert(sna->render.vertex_used);
8642542f5fSchristos	assert(sna->render.vertex_used <= sna->render.vertex_size);
8742542f5fSchristos
8842542f5fSchristos	sna_vertex_wait__locked(&sna->render);
8942542f5fSchristos
9042542f5fSchristos	/* Note: we only need dword alignment (currently) */
9142542f5fSchristos
9242542f5fSchristos	hint = CREATE_GTT_MAP;
9342542f5fSchristos
9442542f5fSchristos	bo = sna->render.vbo;
9542542f5fSchristos	if (bo) {
9642542f5fSchristos		for (i = 0; i < sna->render.nvertex_reloc; i++) {
9742542f5fSchristos			DBG(("%s: reloc[%d] = %d\n", __FUNCTION__,
9842542f5fSchristos			     i, sna->render.vertex_reloc[i]));
9942542f5fSchristos
10042542f5fSchristos			*(uint64_t *)(sna->kgem.batch+sna->render.vertex_reloc[i]) =
10142542f5fSchristos				kgem_add_reloc64(&sna->kgem,
10242542f5fSchristos						 sna->render.vertex_reloc[i], bo,
10342542f5fSchristos						 I915_GEM_DOMAIN_VERTEX << 16,
10442542f5fSchristos						 0);
10542542f5fSchristos		}
10642542f5fSchristos
10742542f5fSchristos		assert(!sna->render.active);
10842542f5fSchristos		sna->render.nvertex_reloc = 0;
10942542f5fSchristos		sna->render.vertex_used = 0;
11042542f5fSchristos		sna->render.vertex_index = 0;
11142542f5fSchristos		sna->render.vbo = NULL;
11242542f5fSchristos		sna->render.vb_id = 0;
11342542f5fSchristos
11442542f5fSchristos		kgem_bo_destroy(&sna->kgem, bo);
11542542f5fSchristos		hint |= CREATE_CACHED | CREATE_NO_THROTTLE;
11642542f5fSchristos	} else {
11742542f5fSchristos		if (kgem_is_idle(&sna->kgem)) {
11842542f5fSchristos			sna->render.vertices = sna->render.vertex_data;
11942542f5fSchristos			sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
12042542f5fSchristos			return 0;
12142542f5fSchristos		}
12242542f5fSchristos	}
12342542f5fSchristos
12442542f5fSchristos	size = 256*1024;
12542542f5fSchristos	assert(!sna->render.active);
12642542f5fSchristos	sna->render.vertices = NULL;
12742542f5fSchristos	sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
12842542f5fSchristos	while (sna->render.vbo == NULL && size > 16*1024) {
12942542f5fSchristos		size /= 2;
13042542f5fSchristos		sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
13142542f5fSchristos	}
13242542f5fSchristos	if (sna->render.vbo == NULL)
13342542f5fSchristos		sna->render.vbo = kgem_create_linear(&sna->kgem,
13442542f5fSchristos						     256*1024, CREATE_GTT_MAP);
13542542f5fSchristos	if (sna->render.vbo)
13642542f5fSchristos		sna->render.vertices = kgem_bo_map(&sna->kgem, sna->render.vbo);
13742542f5fSchristos	if (sna->render.vertices == NULL) {
13842542f5fSchristos		if (sna->render.vbo) {
13942542f5fSchristos			kgem_bo_destroy(&sna->kgem, sna->render.vbo);
14042542f5fSchristos			sna->render.vbo = NULL;
14142542f5fSchristos		}
14242542f5fSchristos		sna->render.vertices = sna->render.vertex_data;
14342542f5fSchristos		sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
14442542f5fSchristos		return 0;
14542542f5fSchristos	}
14642542f5fSchristos
14742542f5fSchristos	if (sna->render.vertex_used) {
14842542f5fSchristos		DBG(("%s: copying initial buffer x %d to handle=%d\n",
14942542f5fSchristos		     __FUNCTION__,
15042542f5fSchristos		     sna->render.vertex_used,
15142542f5fSchristos		     sna->render.vbo->handle));
15242542f5fSchristos		assert(sizeof(float)*sna->render.vertex_used <=
15342542f5fSchristos		       __kgem_bo_size(sna->render.vbo));
15442542f5fSchristos		memcpy(sna->render.vertices,
15542542f5fSchristos		       sna->render.vertex_data,
15642542f5fSchristos		       sizeof(float)*sna->render.vertex_used);
15742542f5fSchristos	}
15842542f5fSchristos
15942542f5fSchristos	size = __kgem_bo_size(sna->render.vbo)/4;
16042542f5fSchristos	if (size >= UINT16_MAX)
16142542f5fSchristos		size = UINT16_MAX - 1;
16242542f5fSchristos
16342542f5fSchristos	DBG(("%s: create vbo handle=%d, size=%d\n",
16442542f5fSchristos	     __FUNCTION__, sna->render.vbo->handle, size));
16542542f5fSchristos
16642542f5fSchristos	sna->render.vertex_size = size;
16742542f5fSchristos	return sna->render.vertex_size - sna->render.vertex_used;
16842542f5fSchristos}
16942542f5fSchristos
17042542f5fSchristosvoid gen8_vertex_close(struct sna *sna)
17142542f5fSchristos{
17242542f5fSchristos	struct kgem_bo *bo, *free_bo = NULL;
17342542f5fSchristos	unsigned int i, delta = 0;
17442542f5fSchristos
17542542f5fSchristos	assert(sna->render.vertex_offset == 0);
17642542f5fSchristos	if (!sna->render.vb_id)
17742542f5fSchristos		return;
17842542f5fSchristos
17942542f5fSchristos	DBG(("%s: used=%d, vbo active? %d, vb=%x, nreloc=%d\n",
18042542f5fSchristos	     __FUNCTION__, sna->render.vertex_used, sna->render.vbo ? sna->render.vbo->handle : 0,
18142542f5fSchristos	     sna->render.vb_id, sna->render.nvertex_reloc));
18242542f5fSchristos
18342542f5fSchristos	assert(!sna->render.active);
18442542f5fSchristos
18542542f5fSchristos	bo = sna->render.vbo;
18642542f5fSchristos	if (bo) {
18742542f5fSchristos		if (sna->render.vertex_size - sna->render.vertex_used < 64) {
18842542f5fSchristos			DBG(("%s: discarding vbo (full), handle=%d\n", __FUNCTION__, sna->render.vbo->handle));
18942542f5fSchristos			sna->render.vbo = NULL;
19042542f5fSchristos			sna->render.vertices = sna->render.vertex_data;
19142542f5fSchristos			sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
19242542f5fSchristos			free_bo = bo;
19342542f5fSchristos		} else if (!sna->kgem.has_llc && sna->render.vertices == MAP(bo->map__cpu)) {
19442542f5fSchristos			DBG(("%s: converting CPU map to GTT\n", __FUNCTION__));
19542542f5fSchristos			sna->render.vertices =
19642542f5fSchristos				kgem_bo_map__gtt(&sna->kgem, sna->render.vbo);
19742542f5fSchristos			if (sna->render.vertices == NULL) {
19842542f5fSchristos				sna->render.vbo = NULL;
19942542f5fSchristos				sna->render.vertices = sna->render.vertex_data;
20042542f5fSchristos				sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
20142542f5fSchristos				free_bo = bo;
20242542f5fSchristos			}
20342542f5fSchristos
20442542f5fSchristos		}
20542542f5fSchristos	} else {
20642542f5fSchristos		int size;
20742542f5fSchristos
20842542f5fSchristos		size  = sna->kgem.nbatch;
20942542f5fSchristos		size += sna->kgem.batch_size - sna->kgem.surface;
21042542f5fSchristos		size += sna->render.vertex_used;
21142542f5fSchristos
21242542f5fSchristos		if (size <= 1024) {
21342542f5fSchristos			DBG(("%s: copy to batch: %d @ %d\n", __FUNCTION__,
21442542f5fSchristos			     sna->render.vertex_used, sna->kgem.nbatch));
21542542f5fSchristos			assert(sna->kgem.nbatch + sna->render.vertex_used <= sna->kgem.surface);
21642542f5fSchristos			memcpy(sna->kgem.batch + sna->kgem.nbatch,
21742542f5fSchristos			       sna->render.vertex_data,
21842542f5fSchristos			       sna->render.vertex_used * 4);
21942542f5fSchristos			delta = sna->kgem.nbatch * 4;
22042542f5fSchristos			bo = NULL;
22142542f5fSchristos			sna->kgem.nbatch += sna->render.vertex_used;
22242542f5fSchristos		} else {
22342542f5fSchristos			size = 256 * 1024;
22442542f5fSchristos			do {
22542542f5fSchristos				bo = kgem_create_linear(&sna->kgem, size,
22642542f5fSchristos							CREATE_GTT_MAP | CREATE_NO_RETIRE | CREATE_NO_THROTTLE | CREATE_CACHED);
22742542f5fSchristos			} while (bo == NULL && (size>>=1) > sizeof(float)*sna->render.vertex_used);
22842542f5fSchristos
22942542f5fSchristos			sna->render.vertices = NULL;
23042542f5fSchristos			if (bo)
23142542f5fSchristos				sna->render.vertices = kgem_bo_map(&sna->kgem, bo);
23242542f5fSchristos			if (sna->render.vertices != NULL) {
23342542f5fSchristos				DBG(("%s: new vbo: %d / %d\n", __FUNCTION__,
23442542f5fSchristos				     sna->render.vertex_used, __kgem_bo_size(bo)/4));
23542542f5fSchristos
23642542f5fSchristos				assert(sizeof(float)*sna->render.vertex_used <= __kgem_bo_size(bo));
23742542f5fSchristos				memcpy(sna->render.vertices,
23842542f5fSchristos				       sna->render.vertex_data,
23942542f5fSchristos				       sizeof(float)*sna->render.vertex_used);
24042542f5fSchristos
24142542f5fSchristos				size = __kgem_bo_size(bo)/4;
24242542f5fSchristos				if (size >= UINT16_MAX)
24342542f5fSchristos					size = UINT16_MAX - 1;
24442542f5fSchristos
24542542f5fSchristos				sna->render.vbo = bo;
24642542f5fSchristos				sna->render.vertex_size = size;
24742542f5fSchristos			} else {
24842542f5fSchristos				DBG(("%s: tmp vbo: %d\n", __FUNCTION__,
24942542f5fSchristos				     sna->render.vertex_used));
25042542f5fSchristos
25142542f5fSchristos				if (bo)
25242542f5fSchristos					kgem_bo_destroy(&sna->kgem, bo);
25342542f5fSchristos
25442542f5fSchristos				bo = kgem_create_linear(&sna->kgem,
25542542f5fSchristos							4*sna->render.vertex_used,
25642542f5fSchristos							CREATE_NO_THROTTLE);
25742542f5fSchristos				if (bo && !kgem_bo_write(&sna->kgem, bo,
25842542f5fSchristos							 sna->render.vertex_data,
25942542f5fSchristos							 4*sna->render.vertex_used)) {
26042542f5fSchristos					kgem_bo_destroy(&sna->kgem, bo);
26142542f5fSchristos					bo = NULL;
26242542f5fSchristos				}
26342542f5fSchristos
26442542f5fSchristos				assert(sna->render.vbo == NULL);
26542542f5fSchristos				sna->render.vertices = sna->render.vertex_data;
26642542f5fSchristos				sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
26742542f5fSchristos				free_bo = bo;
26842542f5fSchristos			}
26942542f5fSchristos		}
27042542f5fSchristos	}
27142542f5fSchristos
27242542f5fSchristos	assert(sna->render.nvertex_reloc);
27342542f5fSchristos	for (i = 0; i < sna->render.nvertex_reloc; i++) {
27442542f5fSchristos		DBG(("%s: reloc[%d] = %d\n", __FUNCTION__,
27542542f5fSchristos		     i, sna->render.vertex_reloc[i]));
27642542f5fSchristos
27742542f5fSchristos		*(uint64_t *)(sna->kgem.batch+sna->render.vertex_reloc[i]) =
27842542f5fSchristos			kgem_add_reloc64(&sna->kgem,
27942542f5fSchristos					 sna->render.vertex_reloc[i], bo,
28042542f5fSchristos					 I915_GEM_DOMAIN_VERTEX << 16,
28142542f5fSchristos					 delta);
28242542f5fSchristos	}
28342542f5fSchristos	sna->render.nvertex_reloc = 0;
28442542f5fSchristos	sna->render.vb_id = 0;
28542542f5fSchristos
28642542f5fSchristos	if (sna->render.vbo == NULL) {
28742542f5fSchristos		assert(!sna->render.active);
28842542f5fSchristos		sna->render.vertex_used = 0;
28942542f5fSchristos		sna->render.vertex_index = 0;
29042542f5fSchristos		assert(sna->render.vertices == sna->render.vertex_data);
29142542f5fSchristos		assert(sna->render.vertex_size == ARRAY_SIZE(sna->render.vertex_data));
29242542f5fSchristos	}
29342542f5fSchristos
29442542f5fSchristos	if (free_bo)
29542542f5fSchristos		kgem_bo_destroy(&sna->kgem, free_bo);
29642542f5fSchristos}
297