350 lines
8.0 KiB
C
350 lines
8.0 KiB
C
/*
|
|
* Copyright (C) 2009-2010 Francisco Jerez.
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial
|
|
* portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include "tnl/t_context.h"
|
|
#include "tnl/t_pipeline.h"
|
|
#include "tnl/t_vertex.h"
|
|
|
|
#define SWTNL_VBO_SIZE 65536
|
|
|
|
static enum tnl_attr_format
|
|
swtnl_get_format(int type, int fields) {
|
|
switch (type) {
|
|
case GL_FLOAT:
|
|
switch (fields){
|
|
case 1:
|
|
return EMIT_1F;
|
|
case 2:
|
|
return EMIT_2F;
|
|
case 3:
|
|
return EMIT_3F;
|
|
case 4:
|
|
return EMIT_4F;
|
|
default:
|
|
assert(0);
|
|
}
|
|
case GL_UNSIGNED_BYTE:
|
|
switch (fields) {
|
|
case 4:
|
|
return EMIT_4UB_4F_RGBA;
|
|
default:
|
|
assert(0);
|
|
}
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
static struct swtnl_attr_info {
|
|
int type;
|
|
int fields;
|
|
} swtnl_attrs[VERT_ATTRIB_MAX] = {
|
|
[VERT_ATTRIB_POS] = {
|
|
.type = GL_FLOAT,
|
|
.fields = 4,
|
|
},
|
|
[VERT_ATTRIB_NORMAL] = {
|
|
.type = GL_FLOAT,
|
|
.fields = -1,
|
|
},
|
|
[VERT_ATTRIB_COLOR0] = {
|
|
.type = GL_UNSIGNED_BYTE,
|
|
.fields = 4,
|
|
},
|
|
[VERT_ATTRIB_COLOR1] = {
|
|
.type = GL_UNSIGNED_BYTE,
|
|
.fields = 4,
|
|
},
|
|
[VERT_ATTRIB_FOG] = {
|
|
.type = GL_FLOAT,
|
|
.fields = 1,
|
|
},
|
|
[VERT_ATTRIB_TEX0] = {
|
|
.type = GL_FLOAT,
|
|
.fields = -1,
|
|
},
|
|
[VERT_ATTRIB_TEX1] = {
|
|
.type = GL_FLOAT,
|
|
.fields = -1,
|
|
},
|
|
[VERT_ATTRIB_TEX2] = {
|
|
.type = GL_FLOAT,
|
|
.fields = -1,
|
|
},
|
|
[VERT_ATTRIB_TEX3] = {
|
|
.type = GL_FLOAT,
|
|
.fields = -1,
|
|
},
|
|
};
|
|
|
|
static void
|
|
swtnl_choose_attrs(struct gl_context *ctx)
|
|
{
|
|
struct nouveau_render_state *render = to_render_state(ctx);
|
|
TNLcontext *tnl = TNL_CONTEXT(ctx);
|
|
struct tnl_clipspace *vtx = &tnl->clipspace;
|
|
static struct tnl_attr_map map[NUM_VERTEX_ATTRS];
|
|
int fields, attr, i, n = 0;
|
|
|
|
render->mode = VBO;
|
|
render->attr_count = NUM_VERTEX_ATTRS;
|
|
|
|
/* We always want non Ndc coords format */
|
|
tnl->vb.AttribPtr[VERT_ATTRIB_POS] = tnl->vb.ClipPtr;
|
|
|
|
for (i = 0; i < VERT_ATTRIB_MAX; i++) {
|
|
struct nouveau_attr_info *ha = &TAG(vertex_attrs)[i];
|
|
struct swtnl_attr_info *sa = &swtnl_attrs[i];
|
|
struct nouveau_array *a = &render->attrs[i];
|
|
|
|
if (!sa->fields)
|
|
continue; /* Unsupported attribute. */
|
|
|
|
if (tnl->render_inputs_bitset & BITFIELD64_BIT(i)) {
|
|
if (sa->fields > 0)
|
|
fields = sa->fields;
|
|
else
|
|
fields = tnl->vb.AttribPtr[i]->size;
|
|
|
|
map[n++] = (struct tnl_attr_map) {
|
|
.attrib = i,
|
|
.format = swtnl_get_format(sa->type, fields),
|
|
};
|
|
|
|
render->map[ha->vbo_index] = i;
|
|
a->attr = i;
|
|
a->fields = fields;
|
|
a->type = sa->type;
|
|
}
|
|
}
|
|
|
|
_tnl_install_attrs(ctx, map, n, NULL, 0);
|
|
|
|
FOR_EACH_BOUND_ATTR(render, i, attr)
|
|
render->attrs[attr].stride = vtx->vertex_size;
|
|
|
|
TAG(render_set_format)(ctx);
|
|
}
|
|
|
|
static void
|
|
swtnl_alloc_vertices(struct gl_context *ctx)
|
|
{
|
|
struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
|
|
|
|
nouveau_bo_ref(NULL, &swtnl->vbo);
|
|
swtnl->buf = nouveau_get_scratch(ctx, SWTNL_VBO_SIZE, &swtnl->vbo,
|
|
&swtnl->offset);
|
|
swtnl->vertex_count = 0;
|
|
}
|
|
|
|
static void
|
|
swtnl_bind_vertices(struct gl_context *ctx)
|
|
{
|
|
struct nouveau_render_state *render = to_render_state(ctx);
|
|
struct nouveau_swtnl_state *swtnl = &render->swtnl;
|
|
struct tnl_clipspace *vtx = &TNL_CONTEXT(ctx)->clipspace;
|
|
int i;
|
|
|
|
for (i = 0; i < vtx->attr_count; i++) {
|
|
struct tnl_clipspace_attr *ta = &vtx->attr[i];
|
|
struct nouveau_array *a = &render->attrs[ta->attrib];
|
|
|
|
nouveau_bo_ref(swtnl->vbo, &a->bo);
|
|
a->offset = swtnl->offset + ta->vertoffset;
|
|
}
|
|
|
|
TAG(render_bind_vertices)(ctx);
|
|
}
|
|
|
|
static void
|
|
swtnl_unbind_vertices(struct gl_context *ctx)
|
|
{
|
|
struct nouveau_render_state *render = to_render_state(ctx);
|
|
int i, attr;
|
|
|
|
TAG(render_release_vertices)(ctx);
|
|
|
|
FOR_EACH_BOUND_ATTR(render, i, attr) {
|
|
nouveau_bo_ref(NULL, &render->attrs[attr].bo);
|
|
render->map[i] = -1;
|
|
}
|
|
|
|
render->attr_count = 0;
|
|
}
|
|
|
|
static void
|
|
swtnl_flush_vertices(struct gl_context *ctx)
|
|
{
|
|
struct nouveau_pushbuf *push = context_push(ctx);
|
|
struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
|
|
unsigned npush, start = 0, count = swtnl->vertex_count;
|
|
RENDER_LOCALS(ctx);
|
|
|
|
swtnl_bind_vertices(ctx);
|
|
|
|
while (count) {
|
|
npush = get_max_vertices(ctx, NULL, PUSH_AVAIL(push));
|
|
npush = MIN2(npush / 12 * 12, count);
|
|
count -= npush;
|
|
|
|
if (!npush) {
|
|
PUSH_KICK(push);
|
|
continue;
|
|
}
|
|
|
|
BATCH_BEGIN(nvgl_primitive(swtnl->primitive));
|
|
EMIT_VBO(L, ctx, start, 0, npush);
|
|
BATCH_END();
|
|
|
|
PUSH_KICK(push);
|
|
}
|
|
|
|
swtnl_alloc_vertices(ctx);
|
|
}
|
|
|
|
/* TnL renderer entry points */
|
|
|
|
static void
|
|
swtnl_start(struct gl_context *ctx)
|
|
{
|
|
swtnl_choose_attrs(ctx);
|
|
}
|
|
|
|
static void
|
|
swtnl_finish(struct gl_context *ctx)
|
|
{
|
|
swtnl_flush_vertices(ctx);
|
|
swtnl_unbind_vertices(ctx);
|
|
}
|
|
|
|
static void
|
|
swtnl_primitive(struct gl_context *ctx, GLenum mode)
|
|
{
|
|
}
|
|
|
|
static void
|
|
swtnl_reset_stipple(struct gl_context *ctx)
|
|
{
|
|
}
|
|
|
|
/* Primitive rendering */
|
|
|
|
#define BEGIN_PRIMITIVE(p, n) \
|
|
struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; \
|
|
int vertex_len = TNL_CONTEXT(ctx)->clipspace.vertex_size; \
|
|
\
|
|
if (swtnl->vertex_count + (n) > SWTNL_VBO_SIZE/vertex_len \
|
|
|| (swtnl->vertex_count && swtnl->primitive != p)) \
|
|
swtnl_flush_vertices(ctx); \
|
|
\
|
|
swtnl->primitive = p;
|
|
|
|
#define OUT_VERTEX(i) do { \
|
|
memcpy(swtnl->buf + swtnl->vertex_count * vertex_len, \
|
|
_tnl_get_vertex(ctx, (i)), vertex_len); \
|
|
swtnl->vertex_count++; \
|
|
} while (0)
|
|
|
|
static void
|
|
swtnl_points(struct gl_context *ctx, GLuint first, GLuint last)
|
|
{
|
|
int i, count;
|
|
|
|
while (first < last) {
|
|
BEGIN_PRIMITIVE(GL_POINTS, last - first);
|
|
|
|
count = MIN2(SWTNL_VBO_SIZE / vertex_len, last - first);
|
|
for (i = 0; i < count; i++)
|
|
OUT_VERTEX(first + i);
|
|
|
|
first += count;
|
|
}
|
|
}
|
|
|
|
static void
|
|
swtnl_line(struct gl_context *ctx, GLuint v1, GLuint v2)
|
|
{
|
|
BEGIN_PRIMITIVE(GL_LINES, 2);
|
|
OUT_VERTEX(v1);
|
|
OUT_VERTEX(v2);
|
|
}
|
|
|
|
static void
|
|
swtnl_triangle(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3)
|
|
{
|
|
BEGIN_PRIMITIVE(GL_TRIANGLES, 3);
|
|
OUT_VERTEX(v1);
|
|
OUT_VERTEX(v2);
|
|
OUT_VERTEX(v3);
|
|
}
|
|
|
|
static void
|
|
swtnl_quad(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4)
|
|
{
|
|
BEGIN_PRIMITIVE(GL_QUADS, 4);
|
|
OUT_VERTEX(v1);
|
|
OUT_VERTEX(v2);
|
|
OUT_VERTEX(v3);
|
|
OUT_VERTEX(v4);
|
|
}
|
|
|
|
/* TnL initialization. */
|
|
void
|
|
TAG(swtnl_init)(struct gl_context *ctx)
|
|
{
|
|
TNLcontext *tnl = TNL_CONTEXT(ctx);
|
|
|
|
tnl->Driver.RunPipeline = _tnl_run_pipeline;
|
|
tnl->Driver.Render.Interp = _tnl_interp;
|
|
tnl->Driver.Render.CopyPV = _tnl_copy_pv;
|
|
tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
|
|
tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine;
|
|
tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
|
|
|
|
tnl->Driver.Render.Start = swtnl_start;
|
|
tnl->Driver.Render.Finish = swtnl_finish;
|
|
tnl->Driver.Render.PrimitiveNotify = swtnl_primitive;
|
|
tnl->Driver.Render.ResetLineStipple = swtnl_reset_stipple;
|
|
|
|
tnl->Driver.Render.Points = swtnl_points;
|
|
tnl->Driver.Render.Line = swtnl_line;
|
|
tnl->Driver.Render.Triangle = swtnl_triangle;
|
|
tnl->Driver.Render.Quad = swtnl_quad;
|
|
|
|
_tnl_init_vertices(ctx, tnl->vb.Size,
|
|
NUM_VERTEX_ATTRS * 4 * sizeof(GLfloat));
|
|
_tnl_need_projected_coords(ctx, GL_FALSE);
|
|
_tnl_allow_vertex_fog(ctx, GL_FALSE);
|
|
|
|
swtnl_alloc_vertices(ctx);
|
|
}
|
|
|
|
void
|
|
TAG(swtnl_destroy)(struct gl_context *ctx)
|
|
{
|
|
nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo);
|
|
}
|