@@ -173,6 +173,14 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) | |||
return NULL; | |||
screen->nvws = nvws; | |||
/* 2D object */ | |||
ret = nvws->grobj_alloc(nvws, NV50_2D, &screen->eng2d); | |||
if (ret) { | |||
NOUVEAU_ERR("Error creating 2D object: %d\n", ret); | |||
nv50_screen_destroy(&screen->pipe); | |||
return NULL; | |||
} | |||
/* 3D object */ | |||
if ((chipset & 0xf0) != 0x50 && (chipset & 0xf0) != 0x80) { | |||
NOUVEAU_ERR("Not a G8x chipset\n"); | |||
@@ -218,6 +226,22 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) | |||
return NULL; | |||
} | |||
/* Static 2D init */ | |||
so = so_new(64, 0); | |||
so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4); | |||
so_data (so, screen->sync->handle); | |||
so_data (so, screen->nvws->channel->vram->handle); | |||
so_data (so, screen->nvws->channel->vram->handle); | |||
so_data (so, screen->nvws->channel->vram->handle); | |||
so_method(so, screen->eng2d, NV50_2D_OPERATION, 1); | |||
so_data (so, NV50_2D_OPERATION_SRCCOPY); | |||
so_method(so, screen->eng2d, 0x0290, 1); | |||
so_data (so, 0); | |||
so_method(so, screen->eng2d, 0x0888, 1); | |||
so_data (so, 1); | |||
so_emit(nvws, so); | |||
so_ref(NULL, &so); | |||
/* Static tesla init */ | |||
so = so_new(256, 20); | |||
@@ -11,6 +11,7 @@ struct nv50_screen { | |||
unsigned cur_pctx; | |||
struct nouveau_grobj *tesla; | |||
struct nouveau_grobj *eng2d; | |||
struct nouveau_notifier *sync; | |||
struct pipe_buffer *constbuf; |
@@ -20,6 +20,9 @@ | |||
* SOFTWARE. | |||
*/ | |||
#define __NOUVEAU_PUSH_H__ | |||
#include <stdint.h> | |||
#include "nouveau/nouveau_pushbuf.h" | |||
#include "nv50_context.h" | |||
#include "pipe/p_defines.h" | |||
#include "pipe/internal/p_winsys_screen.h" | |||
@@ -27,6 +30,118 @@ | |||
#include "util/u_tile.h" | |||
static INLINE int | |||
nv50_format(enum pipe_format format) | |||
{ | |||
switch (format) { | |||
case PIPE_FORMAT_A8R8G8B8_UNORM: | |||
case PIPE_FORMAT_Z24S8_UNORM: | |||
return NV50_2D_DST_FORMAT_32BPP; | |||
case PIPE_FORMAT_X8R8G8B8_UNORM: | |||
return NV50_2D_DST_FORMAT_24BPP; | |||
case PIPE_FORMAT_R5G6B5_UNORM: | |||
return NV50_2D_DST_FORMAT_16BPP; | |||
case PIPE_FORMAT_A8_UNORM: | |||
return NV50_2D_DST_FORMAT_8BPP; | |||
default: | |||
return -1; | |||
} | |||
} | |||
static int | |||
nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) | |||
{ | |||
struct nouveau_channel *chan = screen->nvws->channel; | |||
struct nouveau_grobj *eng2d = screen->eng2d; | |||
struct nouveau_bo *bo; | |||
int format, mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT; | |||
int flags = NOUVEAU_BO_VRAM | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD); | |||
bo = screen->nvws->get_bo(nv50_miptree(ps->texture)->buffer); | |||
if (!bo) | |||
return 1; | |||
format = nv50_format(ps->format); | |||
if (format < 0) | |||
return 1; | |||
if (!bo->tiled) { | |||
BEGIN_RING(chan, eng2d, mthd, 2); | |||
OUT_RING (chan, format); | |||
OUT_RING (chan, 1); | |||
BEGIN_RING(chan, eng2d, mthd + 0x14, 5); | |||
OUT_RING (chan, ps->stride); | |||
OUT_RING (chan, ps->width); | |||
OUT_RING (chan, ps->height); | |||
OUT_RELOCh(chan, bo, ps->offset, flags); | |||
OUT_RELOCl(chan, bo, ps->offset, flags); | |||
} else { | |||
BEGIN_RING(chan, eng2d, mthd, 5); | |||
OUT_RING (chan, format); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
OUT_RING (chan, 0); | |||
BEGIN_RING(chan, eng2d, mthd + 0x18, 4); | |||
OUT_RING (chan, ps->width); | |||
OUT_RING (chan, ps->height); | |||
OUT_RELOCh(chan, bo, ps->offset, flags); | |||
OUT_RELOCl(chan, bo, ps->offset, flags); | |||
} | |||
#if 0 | |||
if (dst) { | |||
BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, surf->width); | |||
OUT_RING (chan, surf->height); | |||
} | |||
#endif | |||
return 0; | |||
} | |||
static int | |||
nv50_surface_do_copy(struct nv50_screen *screen, struct pipe_surface *dst, | |||
int dx, int dy, struct pipe_surface *src, int sx, int sy, | |||
int w, int h) | |||
{ | |||
struct nouveau_channel *chan = screen->nvws->channel; | |||
struct nouveau_grobj *eng2d = screen->eng2d; | |||
int ret; | |||
WAIT_RING (chan, 32); | |||
ret = nv50_surface_set(screen, dst, 1); | |||
if (ret) | |||
return ret; | |||
ret = nv50_surface_set(screen, src, 0); | |||
if (ret) | |||
return ret; | |||
BEGIN_RING(chan, eng2d, 0x088c, 1); | |||
OUT_RING (chan, 0); | |||
BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 4); | |||
OUT_RING (chan, dx); | |||
OUT_RING (chan, dy); | |||
OUT_RING (chan, w); | |||
OUT_RING (chan, h); | |||
BEGIN_RING(chan, eng2d, 0x08c0, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
BEGIN_RING(chan, eng2d, 0x08d0, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, sx); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, sy); | |||
return 0; | |||
} | |||
static void | |||
nv50_surface_copy(struct pipe_context *pipe, boolean flip, | |||
struct pipe_surface *dest, unsigned destx, unsigned desty, | |||
@@ -34,17 +149,19 @@ nv50_surface_copy(struct pipe_context *pipe, boolean flip, | |||
unsigned width, unsigned height) | |||
{ | |||
struct nv50_context *nv50 = (struct nv50_context *)pipe; | |||
struct nouveau_winsys *nvws = nv50->screen->nvws; | |||
struct nv50_screen *screen = nv50->screen; | |||
assert(src->format == dest->format); | |||
if (flip) { | |||
desty += height; | |||
while (height--) { | |||
nvws->surface_copy(nvws, dest, destx, desty--, src, | |||
srcx, srcy++, width, 1); | |||
nv50_surface_do_copy(screen, dest, destx, desty--, src, | |||
srcx, srcy++, width, 1); | |||
} | |||
} else { | |||
nvws->surface_copy(nvws, dest, destx, desty, src, srcx, srcy, | |||
width, height); | |||
nv50_surface_do_copy(screen, dest, destx, desty, src, srcx, | |||
srcy, width, height); | |||
} | |||
} | |||
@@ -54,9 +171,30 @@ nv50_surface_fill(struct pipe_context *pipe, struct pipe_surface *dest, | |||
unsigned height, unsigned value) | |||
{ | |||
struct nv50_context *nv50 = (struct nv50_context *)pipe; | |||
struct nouveau_winsys *nvws = nv50->screen->nvws; | |||
struct nv50_screen *screen = nv50->screen; | |||
struct nouveau_channel *chan = screen->nvws->channel; | |||
struct nouveau_grobj *eng2d = screen->eng2d; | |||
int format, ret; | |||
format = nv50_format(dest->format); | |||
if (format < 0) | |||
return; | |||
WAIT_RING (chan, 32); | |||
ret = nv50_surface_set(screen, dest, 1); | |||
if (ret) | |||
return; | |||
nvws->surface_fill(nvws, dest, destx, desty, width, height, value); | |||
BEGIN_RING(chan, eng2d, 0x0580, 3); | |||
OUT_RING (chan, 4); | |||
OUT_RING (chan, format); | |||
OUT_RING (chan, value); | |||
BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4); | |||
OUT_RING (chan, destx); | |||
OUT_RING (chan, desty); | |||
OUT_RING (chan, width); | |||
OUT_RING (chan, height); | |||
} | |||
static void * |
@@ -10,8 +10,7 @@ C_SOURCES = \ | |||
nouveau_winsys.c \ | |||
nouveau_winsys_pipe.c \ | |||
nouveau_winsys_softpipe.c \ | |||
nv04_surface.c \ | |||
nv50_surface.c | |||
nv04_surface.c | |||
include ./Makefile.template |
@@ -56,7 +56,7 @@ nouveau_channel_context_create(struct nouveau_device *dev) | |||
case 0x50: | |||
case 0x80: | |||
case 0x90: | |||
ret = nouveau_surface_channel_create_nv50(nvc); | |||
/* pipe driver does this */ | |||
break; | |||
default: | |||
ret = nouveau_surface_channel_create_nv04(nvc); | |||
@@ -168,8 +168,7 @@ nouveau_context_init(struct nouveau_screen *nv_screen, | |||
case 0x50: | |||
case 0x80: | |||
case 0x90: | |||
if (nouveau_surface_init_nv50(nv)) | |||
return 1; | |||
/* pipe driver does this */ | |||
break; | |||
default: | |||
if (nouveau_surface_init_nv04(nv)) |
@@ -78,10 +78,7 @@ extern void UNLOCK_HARDWARE(struct nouveau_context *); | |||
extern int | |||
nouveau_surface_channel_create_nv04(struct nouveau_channel_context *); | |||
extern int | |||
nouveau_surface_channel_create_nv50(struct nouveau_channel_context *); | |||
extern int nouveau_surface_init_nv04(struct nouveau_context *); | |||
extern int nouveau_surface_init_nv50(struct nouveau_context *); | |||
extern uint32_t *nouveau_pipe_dma_beginp(struct nouveau_grobj *, int, int); | |||
extern void nouveau_pipe_dma_kickoff(struct nouveau_channel *); |
@@ -1,193 +0,0 @@ | |||
#include "pipe/p_context.h" | |||
#include "pipe/p_format.h" | |||
#include "nouveau_context.h" | |||
static INLINE int | |||
nv50_format(enum pipe_format format) | |||
{ | |||
switch (format) { | |||
case PIPE_FORMAT_A8R8G8B8_UNORM: | |||
case PIPE_FORMAT_Z24S8_UNORM: | |||
return NV50_2D_DST_FORMAT_32BPP; | |||
case PIPE_FORMAT_X8R8G8B8_UNORM: | |||
return NV50_2D_DST_FORMAT_24BPP; | |||
case PIPE_FORMAT_R5G6B5_UNORM: | |||
return NV50_2D_DST_FORMAT_16BPP; | |||
case PIPE_FORMAT_A8_UNORM: | |||
return NV50_2D_DST_FORMAT_8BPP; | |||
default: | |||
return -1; | |||
} | |||
} | |||
static int | |||
nv50_surface_set(struct nouveau_context *nv, struct pipe_surface *surf, int dst) | |||
{ | |||
struct nouveau_channel *chan = nv->nvc->channel; | |||
struct nouveau_grobj *eng2d = nv->nvc->Nv2D; | |||
struct nouveau_bo *bo = nouveau_buffer(surf)->bo; | |||
int surf_format, mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT; | |||
int flags = NOUVEAU_BO_VRAM | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD); | |||
surf_format = nv50_format(surf->format); | |||
if (surf_format < 0) | |||
return 1; | |||
if (!bo->tiled) { | |||
BEGIN_RING(chan, eng2d, mthd, 2); | |||
OUT_RING (chan, surf_format); | |||
OUT_RING (chan, 1); | |||
BEGIN_RING(chan, eng2d, mthd + 0x14, 5); | |||
OUT_RING (chan, surf->stride); | |||
OUT_RING (chan, surf->width); | |||
OUT_RING (chan, surf->height); | |||
OUT_RELOCh(chan, bo, surf->offset, flags); | |||
OUT_RELOCl(chan, bo, surf->offset, flags); | |||
} else { | |||
BEGIN_RING(chan, eng2d, mthd, 5); | |||
OUT_RING (chan, surf_format); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
OUT_RING (chan, 0); | |||
BEGIN_RING(chan, eng2d, mthd + 0x18, 4); | |||
OUT_RING (chan, surf->width); | |||
OUT_RING (chan, surf->height); | |||
OUT_RELOCh(chan, bo, surf->offset, flags); | |||
OUT_RELOCl(chan, bo, surf->offset, flags); | |||
} | |||
#if 0 | |||
if (dst) { | |||
BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, surf->width); | |||
OUT_RING (chan, surf->height); | |||
} | |||
#endif | |||
return 0; | |||
} | |||
static int | |||
nv50_surface_copy_prep(struct nouveau_context *nv, | |||
struct pipe_surface *dst, struct pipe_surface *src) | |||
{ | |||
int ret; | |||
assert(src->format == dst->format); | |||
ret = nv50_surface_set(nv, dst, 1); | |||
if (ret) | |||
return ret; | |||
ret = nv50_surface_set(nv, src, 0); | |||
if (ret) | |||
return ret; | |||
return 0; | |||
} | |||
static void | |||
nv50_surface_copy(struct nouveau_context *nv, unsigned dx, unsigned dy, | |||
unsigned sx, unsigned sy, unsigned w, unsigned h) | |||
{ | |||
struct nouveau_channel *chan = nv->nvc->channel; | |||
struct nouveau_grobj *eng2d = nv->nvc->Nv2D; | |||
BEGIN_RING(chan, eng2d, 0x088c, 1); | |||
OUT_RING (chan, 0); | |||
BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 4); | |||
OUT_RING (chan, dx); | |||
OUT_RING (chan, dy); | |||
OUT_RING (chan, w); | |||
OUT_RING (chan, h); | |||
BEGIN_RING(chan, eng2d, 0x08c0, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, 1); | |||
BEGIN_RING(chan, eng2d, 0x08d0, 4); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, sx); | |||
OUT_RING (chan, 0); | |||
OUT_RING (chan, sy); | |||
} | |||
static void | |||
nv50_surface_copy_done(struct nouveau_context *nv) | |||
{ | |||
FIRE_RING(nv->nvc->channel); | |||
} | |||
static int | |||
nv50_surface_fill(struct nouveau_context *nv, struct pipe_surface *dst, | |||
unsigned dx, unsigned dy, unsigned w, unsigned h, | |||
unsigned value) | |||
{ | |||
struct nouveau_channel *chan = nv->nvc->channel; | |||
struct nouveau_grobj *eng2d = nv->nvc->Nv2D; | |||
int rect_format, ret; | |||
rect_format = nv50_format(dst->format); | |||
if (rect_format < 0) | |||
return 1; | |||
ret = nv50_surface_set(nv, dst, 1); | |||
if (ret) | |||
return ret; | |||
BEGIN_RING(chan, eng2d, 0x0580, 3); | |||
OUT_RING (chan, 4); | |||
OUT_RING (chan, rect_format); | |||
OUT_RING (chan, value); | |||
BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4); | |||
OUT_RING (chan, dx); | |||
OUT_RING (chan, dy); | |||
OUT_RING (chan, dx + w); | |||
OUT_RING (chan, dy + h); | |||
FIRE_RING(chan); | |||
return 0; | |||
} | |||
int | |||
nouveau_surface_channel_create_nv50(struct nouveau_channel_context *nvc) | |||
{ | |||
struct nouveau_channel *chan = nvc->channel; | |||
struct nouveau_grobj *eng2d = NULL; | |||
int ret; | |||
ret = nouveau_grobj_alloc(chan, nvc->next_handle++, NV50_2D, &eng2d); | |||
if (ret) | |||
return ret; | |||
nvc->Nv2D = eng2d; | |||
BEGIN_RING(chan, eng2d, NV50_2D_DMA_NOTIFY, 4); | |||
OUT_RING (chan, nvc->sync_notifier->handle); | |||
OUT_RING (chan, chan->vram->handle); | |||
OUT_RING (chan, chan->vram->handle); | |||
OUT_RING (chan, chan->vram->handle); | |||
BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1); | |||
OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY); | |||
BEGIN_RING(chan, eng2d, 0x0290, 1); | |||
OUT_RING (chan, 0); | |||
BEGIN_RING(chan, eng2d, 0x0888, 1); | |||
OUT_RING (chan, 1); | |||
return 0; | |||
} | |||
int | |||
nouveau_surface_init_nv50(struct nouveau_context *nv) | |||
{ | |||
nv->surface_copy_prep = nv50_surface_copy_prep; | |||
nv->surface_copy = nv50_surface_copy; | |||
nv->surface_copy_done = nv50_surface_copy_done; | |||
nv->surface_fill = nv50_surface_fill; | |||
return 0; | |||
} | |||
@@ -28,18 +28,36 @@ nouveau_copy_buffer(__DRIdrawablePrivate *dPriv, struct pipe_surface *surf, | |||
pbox = dPriv->pClipRects; | |||
nbox = dPriv->numClipRects; | |||
nv->base.surface_copy_prep(&nv->base, nv->base.frontbuffer, surf); | |||
for (i = 0; i < nbox; i++, pbox++) { | |||
int sx, sy, dx, dy, w, h; | |||
sx = pbox->x1 - dPriv->x; | |||
sy = pbox->y1 - dPriv->y; | |||
dx = pbox->x1; | |||
dy = pbox->y1; | |||
w = pbox->x2 - pbox->x1; | |||
h = pbox->y2 - pbox->y1; | |||
nv->base.surface_copy(&nv->base, dx, dy, sx, sy, w, h); | |||
if (nv->base.surface_copy_prep) { | |||
nv->base.surface_copy_prep(&nv->base, nv->base.frontbuffer, surf); | |||
for (i = 0; i < nbox; i++, pbox++) { | |||
int sx, sy, dx, dy, w, h; | |||
sx = pbox->x1 - dPriv->x; | |||
sy = pbox->y1 - dPriv->y; | |||
dx = pbox->x1; | |||
dy = pbox->y1; | |||
w = pbox->x2 - pbox->x1; | |||
h = pbox->y2 - pbox->y1; | |||
nv->base.surface_copy(&nv->base, dx, dy, sx, sy, w, h); | |||
} | |||
} else { | |||
struct pipe_context *pipe = nv->base.nvc->pctx[nv->base.pctx_id]; | |||
for (i = 0; i < nbox; i++, pbox++) { | |||
int sx, sy, dx, dy, w, h; | |||
sx = pbox->x1 - dPriv->x; | |||
sy = pbox->y1 - dPriv->y; | |||
dx = pbox->x1; | |||
dy = pbox->y1; | |||
w = pbox->x2 - pbox->x1; | |||
h = pbox->y2 - pbox->y1; | |||
pipe->surface_copy(pipe, FALSE, nv->base.frontbuffer, | |||
dx, dy, surf, sx, sy, w, h); | |||
} | |||
} | |||
FIRE_RING(nv->base.nvc->channel); |