blob: a62462f7bc5a77dc91315580c93634e66035e766 [file] [log] [blame]
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "pipe/p_util.h"
#include "nv30_context.h"
#include "nv30_state.h"
#include "nouveau/nouveau_channel.h"
#include "nouveau/nouveau_pushbuf.h"
static INLINE int
nv30_vbo_ncomp(uint format)
{
int ncomp = 0;
if (pf_size_x(format)) ncomp++;
if (pf_size_y(format)) ncomp++;
if (pf_size_z(format)) ncomp++;
if (pf_size_w(format)) ncomp++;
return ncomp;
}
static INLINE int
nv30_vbo_type(uint format)
{
switch (pf_type(format)) {
case PIPE_FORMAT_TYPE_FLOAT:
return NV34TCL_VERTEX_ARRAY_FORMAT_TYPE_FLOAT;
case PIPE_FORMAT_TYPE_UNORM:
return NV34TCL_VERTEX_ARRAY_FORMAT_TYPE_UBYTE;
default:
NOUVEAU_ERR("Unknown format 0x%08x\n", format);
return NV40TCL_VTXFMT_TYPE_FLOAT;
}
}
static boolean
nv30_vbo_static_attrib(struct nv30_context *nv30, int attrib,
struct pipe_vertex_element *ve,
struct pipe_vertex_buffer *vb)
{
struct pipe_winsys *ws = nv30->pipe.winsys;
int type, ncomp;
void *map;
type = nv30_vbo_type(ve->src_format);
ncomp = nv30_vbo_ncomp(ve->src_format);
map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
map += vb->buffer_offset + ve->src_offset;
switch (type) {
case NV34TCL_VERTEX_ARRAY_FORMAT_TYPE_FLOAT:
{
float *v = map;
BEGIN_RING(rankine, NV34TCL_VERTEX_ATTR_4F_X(attrib), 4);
switch (ncomp) {
case 4:
OUT_RINGf(v[0]);
OUT_RINGf(v[1]);
OUT_RINGf(v[2]);
OUT_RINGf(v[3]);
break;
case 3:
OUT_RINGf(v[0]);
OUT_RINGf(v[1]);
OUT_RINGf(v[2]);
OUT_RINGf(1.0);
break;
case 2:
OUT_RINGf(v[0]);
OUT_RINGf(v[1]);
OUT_RINGf(0.0);
OUT_RINGf(1.0);
break;
case 1:
OUT_RINGf(v[0]);
OUT_RINGf(0.0);
OUT_RINGf(0.0);
OUT_RINGf(1.0);
break;
default:
ws->buffer_unmap(ws, vb->buffer);
return FALSE;
}
}
break;
default:
ws->buffer_unmap(ws, vb->buffer);
return FALSE;
}
ws->buffer_unmap(ws, vb->buffer);
return TRUE;
}
static void
nv30_vbo_arrays_update(struct nv30_context *nv30)
{
struct nv30_vertex_program *vp = nv30->vertprog.active;
uint32_t inputs, vtxfmt[16];
int hw, num_hw = 0;
nv30->vb_enable = 0;
inputs = vp->ir;
for (hw = 0; hw < 16 && inputs; hw++) {
if (inputs & (1 << hw)) {
num_hw = hw;
inputs &= ~(1 << hw);
}
}
num_hw++;
inputs = vp->ir;
for (hw = 0; hw < num_hw; hw++) {
struct pipe_vertex_element *ve;
struct pipe_vertex_buffer *vb;
if (!(inputs & (1 << hw))) {
vtxfmt[hw] = NV34TCL_VERTEX_ARRAY_FORMAT_TYPE_FLOAT;
continue;
}
ve = &nv30->vtxelt[hw];
vb = &nv30->vtxbuf[ve->vertex_buffer_index];
if (vb->pitch == 0) {
vtxfmt[hw] = NV34TCL_VERTEX_ARRAY_FORMAT_TYPE_FLOAT;
if (nv30_vbo_static_attrib(nv30, hw, ve, vb) == TRUE)
continue;
}
nv30->vb_enable |= (1 << hw);
nv30->vb[hw].delta = vb->buffer_offset + ve->src_offset;
nv30->vb[hw].buffer = vb->buffer;
vtxfmt[hw] = ((vb->pitch << NV34TCL_VERTEX_ARRAY_FORMAT_STRIDE_SHIFT) |
(nv30_vbo_ncomp(ve->src_format) <<
NV34TCL_VERTEX_ARRAY_FORMAT_SIZE_SHIFT) |
nv30_vbo_type(ve->src_format));
}
BEGIN_RING(rankine, NV34TCL_VERTEX_ARRAY_FORMAT(0), num_hw);
OUT_RINGp (vtxfmt, num_hw);
}
static boolean
nv30_vbo_validate_state(struct nv30_context *nv30,
struct pipe_buffer *ib, unsigned ib_format)
{
unsigned inputs;
nv30_emit_hw_state(nv30);
if (nv30->dirty & NV30_NEW_ARRAYS) {
nv30_vbo_arrays_update(nv30);
nv30->dirty &= ~NV30_NEW_ARRAYS;
}
inputs = nv30->vb_enable;
while (inputs) {
unsigned a = ffs(inputs) - 1;
inputs &= ~(1 << a);
BEGIN_RING(rankine, NV34TCL_VERTEX_BUFFER_ADDRESS(a), 1);
OUT_RELOC (nv30->vb[a].buffer, nv30->vb[a].delta,
NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_LOW |
NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
NV34TCL_VERTEX_BUFFER_ADDRESS_DMA1);
}
if (ib) {
BEGIN_RING(rankine, NV40TCL_IDXBUF_ADDRESS, 2);
OUT_RELOCl(ib, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
NOUVEAU_BO_RD);
OUT_RELOCd(ib, ib_format, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
NOUVEAU_BO_RD | NOUVEAU_BO_OR,
0, NV40TCL_IDXBUF_FORMAT_DMA1);
}
BEGIN_RING(rankine, 0x1710, 1);
OUT_RING (0); /* vtx cache flush */
return TRUE;
}
boolean
nv30_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
unsigned count)
{
struct nv30_context *nv30 = nv30_context(pipe);
unsigned nr;
boolean ret;
ret = nv30_vbo_validate_state(nv30, NULL, 0);
if (!ret) {
NOUVEAU_ERR("state validate failed\n");
return FALSE;
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (nvgl_primitive(mode));
nr = (count & 0xff);
if (nr) {
BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
OUT_RING (((nr - 1) << 24) | start);
start += nr;
}
nr = count >> 8;
while (nr) {
unsigned push = nr > 2047 ? 2047 : nr;
nr -= push;
BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
while (push--) {
OUT_RING(((0x100 - 1) << 24) | start);
start += 0x100;
}
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (0);
pipe->flush(pipe, 0);
return TRUE;
}
static INLINE void
nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
unsigned start, unsigned count)
{
uint8_t *elts = (uint8_t *)ib + start;
int push, i;
if (count & 1) {
BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
OUT_RING (elts[0]);
elts++; count--;
}
while (count) {
push = MIN2(count, 2047 * 2);
BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
for (i = 0; i < push; i+=2)
OUT_RING((elts[i+1] << 16) | elts[i]);
count -= push;
elts += push;
}
}
static INLINE void
nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
unsigned start, unsigned count)
{
uint16_t *elts = (uint16_t *)ib + start;
int push, i;
if (count & 1) {
BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
OUT_RING (elts[0]);
elts++; count--;
}
while (count) {
push = MIN2(count, 2047 * 2);
BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
for (i = 0; i < push; i+=2)
OUT_RING((elts[i+1] << 16) | elts[i]);
count -= push;
elts += push;
}
}
static INLINE void
nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
unsigned start, unsigned count)
{
uint32_t *elts = (uint32_t *)ib + start;
int push;
while (count) {
push = MIN2(count, 2047);
BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
OUT_RINGp (elts, push);
count -= push;
elts += push;
}
}
static boolean
nv30_draw_elements_inline(struct pipe_context *pipe,
struct pipe_buffer *ib, unsigned ib_size,
unsigned mode, unsigned start, unsigned count)
{
struct nv30_context *nv30 = nv30_context(pipe);
struct pipe_winsys *ws = pipe->winsys;
boolean ret;
void *map;
ret = nv30_vbo_validate_state(nv30, NULL, 0);
if (!ret) {
NOUVEAU_ERR("state validate failed\n");
return FALSE;
}
map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
if (!ib) {
NOUVEAU_ERR("failed mapping ib\n");
return FALSE;
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (nvgl_primitive(mode));
switch (ib_size) {
case 1:
nv30_draw_elements_u08(nv30, map, start, count);
break;
case 2:
nv30_draw_elements_u16(nv30, map, start, count);
break;
case 4:
nv30_draw_elements_u32(nv30, map, start, count);
break;
default:
NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
break;
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (0);
ws->buffer_unmap(ws, ib);
return TRUE;
}
static boolean
nv30_draw_elements_vbo(struct pipe_context *pipe,
struct pipe_buffer *ib, unsigned ib_size,
unsigned mode, unsigned start, unsigned count)
{
struct nv30_context *nv30 = nv30_context(pipe);
unsigned nr, type;
boolean ret;
switch (ib_size) {
case 2:
type = NV40TCL_IDXBUF_FORMAT_TYPE_U16;
break;
case 4:
type = NV40TCL_IDXBUF_FORMAT_TYPE_U32;
break;
default:
NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
return FALSE;
}
ret = nv30_vbo_validate_state(nv30, ib, type);
if (!ret) {
NOUVEAU_ERR("failed state validation\n");
return FALSE;
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (nvgl_primitive(mode));
nr = (count & 0xff);
if (nr) {
BEGIN_RING(rankine, NV40TCL_VB_INDEX_BATCH, 1);
OUT_RING (((nr - 1) << 24) | start);
start += nr;
}
nr = count >> 8;
while (nr) {
unsigned push = nr > 2047 ? 2047 : nr;
nr -= push;
BEGIN_RING_NI(rankine, NV40TCL_VB_INDEX_BATCH, push);
while (push--) {
OUT_RING(((0x100 - 1) << 24) | start);
start += 0x100;
}
}
BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
OUT_RING (0);
return TRUE;
}
boolean
nv30_draw_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer, unsigned indexSize,
unsigned mode, unsigned start, unsigned count)
{
/* if (indexSize != 1) {
nv30_draw_elements_vbo(pipe, indexBuffer, indexSize,
mode, start, count);
} else */{
nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
mode, start, count);
}
pipe->flush(pipe, 0);
return TRUE;
}