* SOFTWARE.
*/
+#define __NOUVEAU_PUSH_H__
+#include <stdint.h>
+#include "nouveau/nouveau_pushbuf.h"
#include "nv50_context.h"
#include "pipe/p_defines.h"
-#include "pipe/p_winsys.h"
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
#include "util/u_tile.h"
+#include "util/u_format.h"
-static void
-nv50_surface_copy(struct pipe_context *pipe, boolean flip,
- struct pipe_surface *dest, unsigned destx, unsigned desty,
- struct pipe_surface *src, unsigned srcx, unsigned srcy,
- unsigned width, unsigned height)
+static INLINE int
+nv50_format(enum pipe_format format)
{
- struct nv50_context *nv50 = (struct nv50_context *)pipe;
- struct nouveau_winsys *nvws = nv50->screen->nvws;
-
- if (flip) {
- desty += height;
- while (height--) {
- nvws->surface_copy(nvws, dest, destx, desty--, src,
- srcx, srcy++, width, 1);
- }
- } else {
- nvws->surface_copy(nvws, dest, destx, desty, src, srcx, srcy,
- width, height);
+ switch (format) {
+ case PIPE_FORMAT_B8G8R8A8_UNORM:
+ return NV50_2D_DST_FORMAT_A8R8G8B8_UNORM;
+ case PIPE_FORMAT_B8G8R8X8_UNORM:
+ return NV50_2D_DST_FORMAT_X8R8G8B8_UNORM;
+ case PIPE_FORMAT_B8G8R8A8_SRGB:
+ return NV50_2D_DST_FORMAT_A8R8G8B8_SRGB;
+ case PIPE_FORMAT_B8G8R8X8_SRGB:
+ return NV50_2D_DST_FORMAT_X8R8G8B8_SRGB;
+ case PIPE_FORMAT_B5G6R5_UNORM:
+ return NV50_2D_DST_FORMAT_R5G6B5_UNORM;
+ case PIPE_FORMAT_B5G5R5A1_UNORM:
+ return NV50_2D_DST_FORMAT_A1R5G5B5_UNORM;
+ case PIPE_FORMAT_A8_UNORM:
+ case PIPE_FORMAT_I8_UNORM:
+ case PIPE_FORMAT_L8_UNORM:
+ return NV50_2D_DST_FORMAT_R8_UNORM;
+ case PIPE_FORMAT_R32G32B32A32_FLOAT:
+ return NV50_2D_DST_FORMAT_R32G32B32A32_FLOAT;
+ case PIPE_FORMAT_R32G32B32_FLOAT:
+ return NV50_2D_DST_FORMAT_R32G32B32X32_FLOAT;
+ case PIPE_FORMAT_Z32_FLOAT:
+ return NV50_2D_DST_FORMAT_R32_FLOAT;
+
+ /* only because we require src format == dst format: */
+ case PIPE_FORMAT_R16G16_SNORM:
+ case PIPE_FORMAT_R16G16_UNORM:
+ case PIPE_FORMAT_S8Z24_UNORM:
+ case PIPE_FORMAT_Z24S8_UNORM:
+ return NV50_2D_DST_FORMAT_A8R8G8B8_UNORM;
+ case PIPE_FORMAT_L8A8_UNORM:
+ case PIPE_FORMAT_B4G4R4A4_UNORM:
+ return NV50_2D_DST_FORMAT_R16_UNORM;
+
+ default:
+ return -1;
}
}
-static void
-nv50_surface_fill(struct pipe_context *pipe, struct pipe_surface *dest,
- unsigned destx, unsigned desty, unsigned width,
- unsigned height, unsigned value)
+static int
+nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst)
{
- struct nv50_context *nv50 = (struct nv50_context *)pipe;
- struct nouveau_winsys *nvws = nv50->screen->nvws;
+ struct nv50_miptree *mt = nv50_miptree(ps->texture);
+ struct nouveau_channel *chan = screen->eng2d->channel;
+ struct nouveau_grobj *eng2d = screen->eng2d;
+ struct nouveau_bo *bo = nv50_miptree(ps->texture)->base.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);
+
+ format = nv50_format(ps->format);
+ if (format < 0) {
+ NOUVEAU_ERR("invalid/unsupported surface format: %s\n",
+ util_format_name(ps->format));
+ return 1;
+ }
- nvws->surface_fill(nvws, dest, destx, desty, width, height, value);
+ if (!bo->tile_flags) {
+ MARK_RING (chan, 9, 2); /* flush on lack of space or relocs */
+ BEGIN_RING(chan, eng2d, mthd, 2);
+ OUT_RING (chan, format);
+ OUT_RING (chan, 1);
+ BEGIN_RING(chan, eng2d, mthd + 0x14, 5);
+ OUT_RING (chan, mt->level[ps->level].pitch);
+ 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 {
+ MARK_RING (chan, 11, 2); /* flush on lack of space or relocs */
+ BEGIN_RING(chan, eng2d, mthd, 5);
+ OUT_RING (chan, format);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, mt->level[ps->level].tile_mode << 4);
+ 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 void *
-nv50_surface_map(struct pipe_screen *screen, struct pipe_surface *ps,
- unsigned flags )
+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_winsys *nvws = nv50_screen(screen)->nvws;
- struct pipe_winsys *ws = screen->winsys;
- struct nv50_surface *s = nv50_surface(ps);
- struct nv50_surface m = *s;
- void *map;
-
- if (!s->untiled) {
- s->untiled = ws->buffer_create(ws, 0, 0, ps->buffer->size);
-
- m.base.buffer = s->untiled;
- nvws->surface_copy(nvws, &m.base, 0, 0, &s->base, 0, 0,
- ps->width, ps->height);
- }
-
- /* Map original tiled surface to disallow it being validated while
- * untiled mirror is mapped.
- */
- ws->buffer_map(ws, ps->buffer, flags);
-
- map = ws->buffer_map(ws, s->untiled, flags);
- if (!map)
- return NULL;
-
- return map;
+ struct nouveau_channel *chan = screen->eng2d->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_unmap(struct pipe_screen *pscreen, struct pipe_surface *ps)
+nv50_surface_copy(struct pipe_context *pipe,
+ struct pipe_surface *dest, unsigned destx, unsigned desty,
+ struct pipe_surface *src, unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
{
- struct nouveau_winsys *nvws = nv50_screen(pscreen)->nvws;
- struct pipe_winsys *ws = pscreen->winsys;
- struct nv50_surface *s = nv50_surface(ps);
- struct nv50_surface m = *s;
+ struct nv50_context *nv50 = nv50_context(pipe);
+ struct nv50_screen *screen = nv50->screen;
- ws->buffer_unmap(ws, s->untiled);
- ws->buffer_unmap(ws, ps->buffer);
+ assert(src->format == dest->format);
- m.base.buffer = s->untiled;
- nvws->surface_copy(nvws, &s->base, 0, 0, &m.base, 0, 0,
- ps->width, ps->height);
+ nv50_surface_do_copy(screen, dest, destx, desty, src, srcx,
+ srcy, width, height);
+}
- pipe_buffer_reference(pscreen, &s->untiled, NULL);
+static void
+nv50_surface_fill(struct pipe_context *pipe, struct pipe_surface *dest,
+ unsigned destx, unsigned desty, unsigned width,
+ unsigned height, unsigned value)
+{
+ struct nv50_context *nv50 = nv50_context(pipe);
+ struct nv50_screen *screen = nv50->screen;
+ struct nouveau_channel *chan = screen->eng2d->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;
+
+ BEGIN_RING(chan, eng2d, NV50_2D_DRAW_SHAPE, 3);
+ OUT_RING (chan, NV50_2D_DRAW_SHAPE_RECTANGLES);
+ OUT_RING (chan, format);
+ OUT_RING (chan, value);
+ BEGIN_RING(chan, eng2d, NV50_2D_DRAW_POINT32_X(0), 4);
+ OUT_RING (chan, destx);
+ OUT_RING (chan, desty);
+ OUT_RING (chan, width);
+ OUT_RING (chan, height);
}
void
nv50->pipe.surface_fill = nv50_surface_fill;
}
-void
-nv50_surface_init_screen_functions(struct pipe_screen *pscreen)
-{
- pscreen->surface_map = nv50_surface_map;
- pscreen->surface_unmap = nv50_surface_unmap;
-}