@@ -86,8 +86,9 @@ nv50_context_unreference_resources(struct nv50_context *nv50) | |||
for (i = 0; i < nv50->num_textures[s]; ++i) | |||
pipe_sampler_view_reference(&nv50->textures[s][i], NULL); | |||
for (i = 0; i < 16; ++i) | |||
pipe_resource_reference(&nv50->constbuf[s][i], NULL); | |||
for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) | |||
if (!nv50->constbuf[s][i].user) | |||
pipe_resource_reference(&nv50->constbuf[s][i].u.buf, NULL); | |||
} | |||
} | |||
@@ -90,6 +90,7 @@ struct nv50_context { | |||
uint32_t semantic_color; | |||
uint32_t semantic_psize; | |||
int32_t index_bias; | |||
boolean uniform_buffer_bound[3]; | |||
boolean prim_restart; | |||
boolean point_sprite; | |||
boolean rt_serialize; | |||
@@ -113,7 +114,7 @@ struct nv50_context { | |||
struct nv50_program *gmtyprog; | |||
struct nv50_program *fragprog; | |||
struct pipe_resource *constbuf[3][16]; | |||
struct nv50_constbuf constbuf[3][NV50_MAX_PIPE_CONSTBUFS]; | |||
uint16_t constbuf_dirty[3]; | |||
uint16_t constbuf_valid[3]; | |||
@@ -163,6 +164,20 @@ nv50_context_screen(struct nv50_context *nv50) | |||
return nv50_screen(&nv50->base.screen->base); | |||
} | |||
/* return index used in nv50_context arrays for a specific shader type */ | |||
static INLINE unsigned | |||
nv50_context_shader_stage(unsigned pipe) | |||
{ | |||
switch (pipe) { | |||
case PIPE_SHADER_VERTEX: return 0; | |||
case PIPE_SHADER_FRAGMENT: return 1; | |||
case PIPE_SHADER_GEOMETRY: return 2; | |||
case PIPE_SHADER_COMPUTE: return 3; | |||
default: | |||
assert(!"invalid/unhandled shader type"); | |||
return 0; | |||
} | |||
} | |||
/* nv50_context.c */ | |||
struct pipe_context *nv50_create(struct pipe_screen *, void *); |
@@ -196,7 +196,7 @@ nv50_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader, | |||
case PIPE_SHADER_CAP_MAX_CONSTS: | |||
return 65536 / 16; | |||
case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: | |||
return 14; | |||
return NV50_MAX_PIPE_CONSTBUFS; | |||
case PIPE_SHADER_CAP_MAX_ADDRS: | |||
return 1; | |||
case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: | |||
@@ -437,10 +437,7 @@ nv50_screen_init_hwctx(struct nv50_screen *screen, unsigned tls_space) | |||
PUSH_DATA (push, screen->uniforms->offset + (3 << 16)); | |||
PUSH_DATA (push, (NV50_CB_AUX << 16) | 0x0200); | |||
BEGIN_NI04(push, NV50_3D(SET_PROGRAM_CB), 6); | |||
PUSH_DATA (push, (NV50_CB_PVP << 12) | 0x001); | |||
PUSH_DATA (push, (NV50_CB_PGP << 12) | 0x021); | |||
PUSH_DATA (push, (NV50_CB_PFP << 12) | 0x031); | |||
BEGIN_NI04(push, NV50_3D(SET_PROGRAM_CB), 3); | |||
PUSH_DATA (push, (NV50_CB_AUX << 12) | 0xf01); | |||
PUSH_DATA (push, (NV50_CB_AUX << 12) | 0xf21); | |||
PUSH_DATA (push, (NV50_CB_AUX << 12) | 0xf31); |
@@ -12,6 +12,9 @@ | |||
#define NV50_TIC_MAX_ENTRIES 2048 | |||
#define NV50_TSC_MAX_ENTRIES 2048 | |||
/* doesn't count reserved slots (for auxiliary constants, immediates, etc.) */ | |||
#define NV50_MAX_PIPE_CONSTBUFS 14 | |||
struct nv50_context; | |||
#define NV50_CODE_BO_SIZE_LOG2 19 |
@@ -35,9 +35,7 @@ nv50_constbufs_validate(struct nv50_context *nv50) | |||
unsigned s; | |||
for (s = 0; s < 3; ++s) { | |||
struct nv04_resource *res; | |||
int i; | |||
unsigned p, b; | |||
unsigned p; | |||
if (s == PIPE_SHADER_FRAGMENT) | |||
p = NV50_3D_SET_PROGRAM_CB_PROGRAM_FRAGMENT; | |||
@@ -48,68 +46,63 @@ nv50_constbufs_validate(struct nv50_context *nv50) | |||
p = NV50_3D_SET_PROGRAM_CB_PROGRAM_VERTEX; | |||
while (nv50->constbuf_dirty[s]) { | |||
struct nouveau_bo *bo; | |||
unsigned start = 0; | |||
unsigned words = 0; | |||
i = ffs(nv50->constbuf_dirty[s]) - 1; | |||
const int i = ffs(nv50->constbuf_dirty[s]) - 1; | |||
nv50->constbuf_dirty[s] &= ~(1 << i); | |||
res = nv04_resource(nv50->constbuf[s][i]); | |||
if (!res) { | |||
if (i != 0) { | |||
if (nv50->constbuf[s][i].user) { | |||
const unsigned b = NV50_CB_PVP + s; | |||
unsigned start = 0; | |||
unsigned words = nv50->constbuf[s][0].size / 4; | |||
if (i) { | |||
NOUVEAU_ERR("user constbufs only supported in slot 0\n"); | |||
continue; | |||
} | |||
if (!nv50->state.uniform_buffer_bound[s]) { | |||
nv50->state.uniform_buffer_bound[s] = TRUE; | |||
BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); | |||
PUSH_DATA (push, (i << 8) | p | 0); | |||
PUSH_DATA (push, (b << 12) | (i << 8) | p | 1); | |||
} | |||
while (words) { | |||
unsigned nr; | |||
if (!PUSH_SPACE(push, 16)) | |||
break; | |||
nr = PUSH_AVAIL(push); | |||
assert(nr >= 16); | |||
nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN); | |||
BEGIN_NV04(push, NV50_3D(CB_ADDR), 1); | |||
PUSH_DATA (push, (start << 8) | b); | |||
BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr); | |||
PUSH_DATAp(push, &nv50->constbuf[s][0].u.data[start * 4], nr); | |||
start += nr; | |||
words -= nr; | |||
} | |||
continue; | |||
} | |||
if (i == 0) { | |||
b = NV50_CB_PVP + s; | |||
/* always upload GL uniforms through CB DATA */ | |||
bo = nv50->screen->uniforms; | |||
words = res->base.width0 / 4; | |||
} else { | |||
b = s * 16 + i; | |||
assert(0); | |||
if (!nouveau_resource_mapped_by_gpu(&res->base)) { | |||
nouveau_buffer_migrate(&nv50->base, res, NOUVEAU_BO_VRAM); | |||
struct nv04_resource *res = | |||
nv04_resource(nv50->constbuf[s][i].u.buf); | |||
if (res) { | |||
/* TODO: allocate persistent bindings */ | |||
const unsigned b = s * 16 + i; | |||
assert(nouveau_resource_mapped_by_gpu(&res->base)); | |||
BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3); | |||
PUSH_DATAh(push, res->address + nv50->constbuf[s][i].offset); | |||
PUSH_DATA (push, res->address + nv50->constbuf[s][i].offset); | |||
PUSH_DATA (push, (b << 16) | | |||
(nv50->constbuf[s][i].size & 0xffff)); | |||
BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); | |||
PUSH_DATA (push, (b << 12) | (i << 8) | p | 1); | |||
BEGIN_NV04(push, NV50_3D(CODE_CB_FLUSH), 1); | |||
PUSH_DATA (push, 0); | |||
BCTX_REFN(nv50->bufctx_3d, CB(s, i), res, RD); | |||
} else { | |||
BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); | |||
PUSH_DATA (push, (i << 8) | p | 0); | |||
} | |||
BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3); | |||
PUSH_DATAh(push, res->address); | |||
PUSH_DATA (push, res->address); | |||
PUSH_DATA (push, (b << 16) | (res->base.width0 & 0xffff)); | |||
BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); | |||
PUSH_DATA (push, (b << 12) | (i << 8) | p | 1); | |||
bo = res->bo; | |||
} | |||
if (bo != nv50->screen->uniforms) | |||
BCTX_REFN(nv50->bufctx_3d, CB(s, i), res, RD); | |||
while (words) { | |||
unsigned nr; | |||
if (!PUSH_SPACE(push, 16)) | |||
break; | |||
nr = PUSH_AVAIL(push); | |||
assert(nr >= 16); | |||
nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN); | |||
BEGIN_NV04(push, NV50_3D(CB_ADDR), 1); | |||
PUSH_DATA (push, (start << 8) | b); | |||
BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr); | |||
PUSH_DATAp(push, &res->data[start * 4], nr); | |||
start += nr; | |||
words -= nr; | |||
if (i == 0) | |||
nv50->state.uniform_buffer_bound[s] = FALSE; | |||
} | |||
} | |||
} |
@@ -751,28 +751,36 @@ nv50_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index, | |||
{ | |||
struct nv50_context *nv50 = nv50_context(pipe); | |||
struct pipe_resource *res = cb ? cb->buffer : NULL; | |||
const unsigned s = nv50_context_shader_stage(shader); | |||
const unsigned i = index; | |||
if (cb && cb->user_buffer) { | |||
res = nouveau_user_buffer_create(pipe->screen, cb->user_buffer, | |||
cb->buffer_size, | |||
PIPE_BIND_CONSTANT_BUFFER); | |||
} | |||
pipe_resource_reference(&nv50->constbuf[shader][index], res); | |||
if (shader == PIPE_SHADER_COMPUTE) | |||
return; | |||
nv50->constbuf_dirty[shader] |= 1 << index; | |||
if (res) | |||
nv50->constbuf_valid[shader] |= 1 << index; | |||
if (nv50->constbuf[s][i].user) | |||
nv50->constbuf[s][i].u.buf = NULL; | |||
else | |||
nv50->constbuf_valid[shader] &= ~(1 << index); | |||
nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_CB(shader, index)); | |||
if (nv50->constbuf[s][i].u.buf) | |||
nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_CB(s, i)); | |||
pipe_resource_reference(&nv50->constbuf[s][i].u.buf, res); | |||
nv50->constbuf[s][i].user = (cb && cb->user_buffer) ? TRUE : FALSE; | |||
if (nv50->constbuf[s][i].user) { | |||
nv50->constbuf[s][i].u.data = cb->user_buffer; | |||
nv50->constbuf[s][i].size = cb->buffer_size; | |||
nv50->constbuf_valid[s] |= 1 << i; | |||
} else | |||
if (res) { | |||
nv50->constbuf[s][i].offset = cb->buffer_offset; | |||
nv50->constbuf[s][i].size = align(cb->buffer_size, 0x100); | |||
nv50->constbuf_valid[s] |= 1 << i; | |||
} else { | |||
nv50->constbuf_valid[s] &= ~(1 << i); | |||
} | |||
nv50->constbuf_dirty[s] |= 1 << i; | |||
nv50->dirty |= NV50_NEW_CONSTBUF; | |||
if (cb && cb->user_buffer) { | |||
pipe_resource_reference(&res, NULL); | |||
} | |||
} | |||
/* ============================================================================= |
@@ -34,6 +34,16 @@ struct nv50_zsa_stateobj { | |||
uint32_t state[29]; | |||
}; | |||
struct nv50_constbuf { | |||
union { | |||
struct pipe_resource *buf; | |||
const uint8_t *data; | |||
} u; | |||
uint32_t size; /* max 65536 */ | |||
uint16_t offset; | |||
boolean user; /* should only be TRUE if u.data is valid and non-NULL */ | |||
}; | |||
struct nv50_vertex_element { | |||
struct pipe_vertex_element pipe; | |||
uint32_t state; |
@@ -72,8 +72,9 @@ nvc0_context_unreference_resources(struct nvc0_context *nvc0) | |||
for (i = 0; i < nvc0->num_textures[s]; ++i) | |||
pipe_sampler_view_reference(&nvc0->textures[s][i], NULL); | |||
for (i = 0; i < 16; ++i) | |||
pipe_resource_reference(&nvc0->constbuf[s][i], NULL); | |||
for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i) | |||
if (!nvc0->constbuf[s][i].user) | |||
pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, NULL); | |||
} | |||
for (i = 0; i < nvc0->num_tfbbufs; ++i) |
@@ -121,7 +121,7 @@ struct nvc0_context { | |||
struct nvc0_program *gmtyprog; | |||
struct nvc0_program *fragprog; | |||
struct pipe_resource *constbuf[5][16]; | |||
struct nvc0_constbuf constbuf[5][NVC0_MAX_PIPE_CONSTBUFS]; | |||
uint16_t constbuf_dirty[5]; | |||
struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS]; | |||
@@ -168,6 +168,23 @@ nvc0_context(struct pipe_context *pipe) | |||
return (struct nvc0_context *)pipe; | |||
} | |||
static INLINE unsigned | |||
nvc0_shader_stage(unsigned pipe) | |||
{ | |||
switch (pipe) { | |||
case PIPE_SHADER_VERTEX: return 0; | |||
/* case PIPE_SHADER_TESSELLATION_CONTROL: return 1; */ | |||
/* case PIPE_SHADER_TESSELLATION_EVALUATION: return 2; */ | |||
case PIPE_SHADER_GEOMETRY: return 3; | |||
case PIPE_SHADER_FRAGMENT: return 4; | |||
case PIPE_SHADER_COMPUTE: return 5; | |||
default: | |||
assert(!"invalid PIPE_SHADER type"); | |||
return 0; | |||
} | |||
} | |||
/* nvc0_context.c */ | |||
struct pipe_context *nvc0_create(struct pipe_screen *, void *); | |||
void nvc0_bufctx_fence(struct nvc0_context *, struct nouveau_bufctx *, |
@@ -190,7 +190,7 @@ nvc0_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader, | |||
case PIPE_SHADER_CAP_MAX_CONSTS: | |||
return 65536 / 16; | |||
case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: | |||
return 14; | |||
return NVC0_MAX_PIPE_CONSTBUFS; | |||
case PIPE_SHADER_CAP_MAX_ADDRS: | |||
return 1; | |||
case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: |
@@ -14,6 +14,9 @@ | |||
#define NVC0_TIC_MAX_ENTRIES 2048 | |||
#define NVC0_TSC_MAX_ENTRIES 2048 | |||
/* doesn't count reserved slots (for auxiliary constants, immediates, etc.) */ | |||
#define NVC0_MAX_PIPE_CONSTBUFS 14 | |||
struct nvc0_context; | |||
struct nvc0_blitctx; |
@@ -620,38 +620,33 @@ nvc0_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index, | |||
{ | |||
struct nvc0_context *nvc0 = nvc0_context(pipe); | |||
struct pipe_resource *res = cb ? cb->buffer : NULL; | |||
const unsigned s = nvc0_shader_stage(shader); | |||
const unsigned i = index; | |||
if (cb && cb->user_buffer) { | |||
res = nouveau_user_buffer_create(pipe->screen, cb->user_buffer, | |||
cb->buffer_size, | |||
PIPE_BIND_CONSTANT_BUFFER); | |||
} | |||
if (shader == PIPE_SHADER_COMPUTE) | |||
return; | |||
switch (shader) { | |||
case PIPE_SHADER_VERTEX: shader = 0; break; | |||
/* | |||
case PIPE_SHADER_TESSELLATION_CONTROL: shader = 1; break; | |||
case PIPE_SHADER_TESSELLATION_EVALUATION: shader = 2; break; | |||
*/ | |||
case PIPE_SHADER_GEOMETRY: shader = 3; break; | |||
case PIPE_SHADER_FRAGMENT: shader = 4; break; | |||
default: | |||
assert(0); | |||
break; | |||
} | |||
if (nvc0->constbuf[s][i].user) | |||
nvc0->constbuf[s][i].u.buf = NULL; | |||
else | |||
if (nvc0->constbuf[s][i].u.buf) | |||
nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_CB(s, i)); | |||
if (nvc0->constbuf[shader][index]) | |||
nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_CB(shader, index)); | |||
pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, res); | |||
pipe_resource_reference(&nvc0->constbuf[shader][index], res); | |||
nvc0->constbuf[s][i].user = (cb && cb->user_buffer) ? TRUE : FALSE; | |||
if (nvc0->constbuf[s][i].user) { | |||
nvc0->constbuf[s][i].u.data = cb->user_buffer; | |||
nvc0->constbuf[s][i].size = cb->buffer_size; | |||
} else | |||
if (cb) { | |||
nvc0->constbuf[s][i].offset = cb->buffer_offset; | |||
nvc0->constbuf[s][i].size = align(cb->buffer_size, 0x100); | |||
} | |||
nvc0->constbuf_dirty[shader] |= 1 << index; | |||
nvc0->constbuf_dirty[s] |= 1 << i; | |||
nvc0->dirty |= NVC0_NEW_CONSTBUF; | |||
if (cb->user_buffer) { | |||
pipe_resource_reference(&res, NULL); | |||
} | |||
} | |||
/* ============================================================================= |
@@ -355,70 +355,53 @@ static void | |||
nvc0_constbufs_validate(struct nvc0_context *nvc0) | |||
{ | |||
struct nouveau_pushbuf *push = nvc0->base.pushbuf; | |||
struct nouveau_bo *bo; | |||
unsigned s; | |||
for (s = 0; s < 5; ++s) { | |||
struct nv04_resource *res; | |||
int i; | |||
while (nvc0->constbuf_dirty[s]) { | |||
unsigned base = 0; | |||
unsigned words = 0; | |||
boolean rebind = TRUE; | |||
i = ffs(nvc0->constbuf_dirty[s]) - 1; | |||
int i = ffs(nvc0->constbuf_dirty[s]) - 1; | |||
nvc0->constbuf_dirty[s] &= ~(1 << i); | |||
res = nv04_resource(nvc0->constbuf[s][i]); | |||
if (!res) { | |||
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); | |||
PUSH_DATA (push, (i << 4) | 0); | |||
if (i == 0) | |||
nvc0->state.uniform_buffer_bound[s] = 0; | |||
continue; | |||
} | |||
if (!nouveau_resource_mapped_by_gpu(&res->base)) { | |||
if (i == 0 && (res->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY)) { | |||
base = s << 16; | |||
bo = nvc0->screen->uniform_bo; | |||
if (nvc0->state.uniform_buffer_bound[s] >= res->base.width0) | |||
rebind = FALSE; | |||
else | |||
nvc0->state.uniform_buffer_bound[s] = | |||
align(res->base.width0, 0x100); | |||
words = res->base.width0 / 4; | |||
} else { | |||
nouveau_buffer_migrate(&nvc0->base, res, NOUVEAU_BO_VRAM); | |||
bo = res->bo; | |||
base = res->offset; | |||
if (nvc0->constbuf[s][i].user) { | |||
struct nouveau_bo *bo = nvc0->screen->uniform_bo; | |||
const unsigned base = s << 16; | |||
const unsigned size = nvc0->constbuf[s][0].size; | |||
assert(i == 0); /* we really only want OpenGL uniforms here */ | |||
assert(nvc0->constbuf[s][0].u.data); | |||
if (nvc0->state.uniform_buffer_bound[s] < size) { | |||
nvc0->state.uniform_buffer_bound[s] = align(size, 0x100); | |||
BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); | |||
PUSH_DATA (push, nvc0->state.uniform_buffer_bound[s]); | |||
PUSH_DATAh(push, bo->offset + base); | |||
PUSH_DATA (push, bo->offset + base); | |||
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); | |||
PUSH_DATA (push, (0 << 4) | 1); | |||
} | |||
nvc0_cb_push(&nvc0->base, bo, NOUVEAU_BO_VRAM, | |||
base, nvc0->state.uniform_buffer_bound[s], | |||
0, (size + 3) / 4, | |||
nvc0->constbuf[s][0].u.data); | |||
} else { | |||
bo = res->bo; | |||
base = res->offset; | |||
struct nv04_resource *res = | |||
nv04_resource(nvc0->constbuf[s][i].u.buf); | |||
if (res) { | |||
BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); | |||
PUSH_DATA (push, nvc0->constbuf[s][i].size); | |||
PUSH_DATAh(push, res->address + nvc0->constbuf[s][i].offset); | |||
PUSH_DATA (push, res->address + nvc0->constbuf[s][i].offset); | |||
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); | |||
PUSH_DATA (push, (i << 4) | 1); | |||
BCTX_REFN(nvc0->bufctx_3d, CB(s, i), res, RD); | |||
} else { | |||
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); | |||
PUSH_DATA (push, (i << 4) | 0); | |||
} | |||
if (i == 0) | |||
nvc0->state.uniform_buffer_bound[s] = 0; | |||
} | |||
if (bo != nvc0->screen->uniform_bo) | |||
BCTX_REFN(nvc0->bufctx_3d, CB(s, i), res, RD); | |||
if (rebind) { | |||
BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); | |||
PUSH_DATA (push, align(res->base.width0, 0x100)); | |||
PUSH_DATAh(push, bo->offset + base); | |||
PUSH_DATA (push, bo->offset + base); | |||
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); | |||
PUSH_DATA (push, (i << 4) | 1); | |||
} | |||
if (words) | |||
nvc0_cb_push(&nvc0->base, | |||
bo, NOUVEAU_BO_VRAM, base, res->base.width0, | |||
0, words, (const uint32_t *)res->data); | |||
} | |||
} | |||
} |
@@ -32,6 +32,16 @@ struct nvc0_zsa_stateobj { | |||
uint32_t state[26]; | |||
}; | |||
struct nvc0_constbuf { | |||
union { | |||
struct pipe_resource *buf; | |||
const void *data; | |||
} u; | |||
uint32_t size; | |||
uint16_t offset; | |||
boolean user; /* should only be TRUE if u.data is valid and non-NULL */ | |||
}; | |||
struct nvc0_vertex_element { | |||
struct pipe_vertex_element pipe; | |||
uint32_t state; |