summaryrefslogtreecommitdiff
path: root/src/mesa/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/Makefile42
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c282
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c123
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c250
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h105
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c144
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h29
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c187
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h158
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h28
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h303
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c173
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c107
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h78
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c94
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c140
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c227
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_resource.c111
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c249
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h19
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c86
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h10
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c143
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c229
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h23
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c82
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nv04_surface.c231
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nv50_surface.c170
28 files changed, 3823 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/nouveau_winsys/Makefile b/src/mesa/drivers/dri/nouveau_winsys/Makefile
new file mode 100644
index 0000000000..f2490c823d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/Makefile
@@ -0,0 +1,42 @@
+
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = nouveau_dri.so
+
+MINIGLX_SOURCES =
+
+PIPE_DRIVERS = \
+ $(TOP)/src/mesa/pipe/softpipe/libsoftpipe.a \
+ $(TOP)/src/mesa/pipe/nv40/libnv40.a \
+ $(TOP)/src/mesa/pipe/nv50/libnv50.a
+
+DRIVER_SOURCES = \
+ nouveau_bo.c \
+ nouveau_channel.c \
+ nouveau_context.c \
+ nouveau_device.c \
+ nouveau_dma.c \
+ nouveau_fence.c \
+ nouveau_grobj.c \
+ nouveau_lock.c \
+ nouveau_notifier.c \
+ nouveau_pushbuf.c \
+ nouveau_resource.c \
+ nouveau_screen.c \
+ nouveau_swapbuffers.c \
+ nouveau_winsys.c \
+ nouveau_winsys_pipe.c \
+ nouveau_winsys_softpipe.c \
+ nv04_surface.c \
+ nv50_surface.c
+
+C_SOURCES = \
+ $(COMMON_SOURCES) \
+ $(DRIVER_SOURCES)
+
+ASM_SOURCES =
+
+include ../Makefile.template
+
+symlinks:
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c
new file mode 100644
index 0000000000..d684ab4d7c
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+#include "nouveau_local.h"
+
+int
+nouveau_bo_init(struct nouveau_device *userdev)
+{
+ return 0;
+}
+
+void
+nouveau_bo_takedown(struct nouveau_device *userdev)
+{
+}
+
+static int
+nouveau_bo_realloc_gpu(struct nouveau_bo_priv *bo, uint32_t flags, int size)
+{
+ struct nouveau_device_priv *nv = nouveau_device(bo->base.device);
+ int ret;
+
+ if (bo->drm.size && bo->drm.size != size) {
+ struct drm_nouveau_mem_free f;
+
+ if (bo->map) {
+ drmUnmap(bo->map, bo->drm.size);
+ bo->map = NULL;
+ }
+
+ f.flags = bo->drm.flags;
+ f.offset = bo->drm.offset;
+ drmCommandWrite(nv->fd, DRM_NOUVEAU_MEM_FREE, &f, sizeof(f));
+
+ bo->drm.size = 0;
+ }
+
+ if (size && !bo->drm.size) {
+ if (flags) {
+ bo->drm.flags = 0;
+ if (flags & NOUVEAU_BO_VRAM)
+ bo->drm.flags |= NOUVEAU_MEM_FB;
+ if (flags & NOUVEAU_BO_GART)
+ bo->drm.flags |= (NOUVEAU_MEM_AGP |
+ NOUVEAU_MEM_PCI);
+ bo->drm.flags |= NOUVEAU_MEM_MAPPED;
+ }
+
+ bo->drm.size = size;
+
+ ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_MEM_ALLOC,
+ &bo->drm, sizeof(bo->drm));
+ if (ret) {
+ free(bo);
+ return ret;
+ }
+
+ ret = drmMap(nv->fd, bo->drm.map_handle, bo->drm.size,
+ &bo->map);
+ if (ret) {
+ bo->map = NULL;
+ nouveau_bo_del((void *)&bo);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+nouveau_bo_new(struct nouveau_device *userdev, uint32_t flags, int align,
+ int size, struct nouveau_bo **userbo)
+{
+ struct nouveau_bo_priv *bo;
+ int ret;
+
+ if (!userdev || !userbo || *userbo)
+ return -EINVAL;
+
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return -ENOMEM;
+ bo->base.device = userdev;
+ bo->drm.alignment = align;
+
+ if (flags & NOUVEAU_BO_PIN) {
+ ret = nouveau_bo_realloc_gpu(bo, flags, size);
+ if (ret) {
+ free(bo);
+ return ret;
+ }
+ } else {
+ bo->sysmem = malloc(size);
+ if (!bo->sysmem) {
+ free(bo);
+ return -ENOMEM;
+ }
+ }
+
+ bo->base.size = size;
+ bo->base.offset = bo->drm.offset;
+ bo->base.handle = (unsigned long)bo;
+ bo->refcount = 1;
+ *userbo = &bo->base;
+ return 0;
+}
+
+int
+nouveau_bo_user(struct nouveau_device *userdev, void *ptr, int size,
+ struct nouveau_bo **userbo)
+{
+ struct nouveau_bo_priv *bo;
+
+ if (!userdev || !userbo || *userbo)
+ return -EINVAL;
+
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return -ENOMEM;
+ bo->base.device = userdev;
+
+ bo->sysmem = ptr;
+ bo->user = 1;
+
+ bo->base.size = size;
+ bo->base.offset = bo->drm.offset;
+ bo->base.handle = (unsigned long)bo;
+ bo->refcount = 1;
+ *userbo = &bo->base;
+ return 0;
+}
+
+int
+nouveau_bo_ref(struct nouveau_device *userdev, uint64_t handle,
+ struct nouveau_bo **userbo)
+{
+ struct nouveau_bo_priv *bo = (void *)(unsigned long)handle;
+
+ if (!userdev || !userbo || *userbo)
+ return -EINVAL;
+
+ bo->refcount++;
+ *userbo = &bo->base;
+ return 0;
+}
+
+int
+nouveau_bo_resize(struct nouveau_bo *userbo, int size)
+{
+ struct nouveau_bo_priv *bo = nouveau_bo(userbo);
+ int ret;
+
+ if (!bo || bo->user)
+ return -EINVAL;
+
+ if (bo->sysmem) {
+ bo->sysmem = realloc(bo->sysmem, size);
+ if (!bo->sysmem)
+ return -ENOMEM;
+ } else {
+ ret = nouveau_bo_realloc_gpu(bo, 0, size);
+ if (ret)
+ return ret;
+ }
+
+ bo->base.size = size;
+ return 0;
+}
+
+void
+nouveau_bo_del(struct nouveau_bo **userbo)
+{
+ struct nouveau_bo_priv *bo;
+
+ if (!userbo || !*userbo)
+ return;
+ bo = nouveau_bo(*userbo);
+ *userbo = NULL;
+
+ if (--bo->refcount)
+ return;
+
+ if (bo->fence)
+ nouveau_fence_wait(&bo->fence);
+
+ nouveau_bo_realloc_gpu(bo, 0, 0);
+ if (bo->sysmem && !bo->user)
+ free(bo->sysmem);
+ free(bo);
+}
+
+int
+nouveau_bo_map(struct nouveau_bo *userbo, uint32_t flags)
+{
+ struct nouveau_bo_priv *bo = nouveau_bo(userbo);
+
+ if (!bo)
+ return -EINVAL;
+
+ if (bo->sysmem)
+ userbo->map = bo->sysmem;
+ else
+ userbo->map = bo->map;
+ return 0;
+}
+
+void
+nouveau_bo_unmap(struct nouveau_bo *userbo)
+{
+ userbo->map = NULL;
+}
+
+static int
+nouveau_bo_upload(struct nouveau_bo_priv *bo)
+{
+ if (bo->fence)
+ nouveau_fence_wait(&bo->fence);
+ memcpy(bo->map, bo->sysmem, bo->drm.size);
+ return 0;
+}
+
+int
+nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo,
+ struct nouveau_fence *fence, uint32_t flags)
+{
+ struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+ if (!nvbo->drm.size) {
+ nouveau_bo_realloc_gpu(nvbo, flags, nvbo->base.size);
+ nouveau_bo_upload(nvbo);
+ } else
+ if (nvbo->user) {
+ nouveau_bo_upload(nvbo);
+ } else
+ if (nvbo->base.map) {
+ nouveau_bo_upload(nvbo);
+ nvbo->sync_hack = 1;
+ }
+
+ if (!nvbo->user && !nvbo->base.map) {
+ free(nvbo->sysmem);
+ nvbo->sysmem = NULL;
+ }
+
+ if (nvbo->fence)
+ nouveau_fence_del(&nvbo->fence);
+ nouveau_fence_ref(fence, &nvbo->fence);
+
+ nvbo->base.offset = nvbo->drm.offset;
+ if (nvbo->drm.flags & NOUVEAU_MEM_AGP)
+ nvbo->base.flags = NOUVEAU_BO_GART;
+ else
+ nvbo->base.flags = NOUVEAU_BO_VRAM;
+
+ return 0;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
new file mode 100644
index 0000000000..c4558e5573
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+
+int
+nouveau_channel_alloc(struct nouveau_device *userdev, uint32_t fb_ctxdma,
+ uint32_t tt_ctxdma, struct nouveau_channel **userchan)
+{
+ struct nouveau_device_priv *nv = nouveau_device(userdev);
+ struct nouveau_channel_priv *chan;
+ int ret;
+
+ if (!nv || !userchan || *userchan)
+ return -EINVAL;
+
+ chan = calloc(1, sizeof(*chan));
+ if (!chan)
+ return -ENOMEM;
+ chan->base.device = userdev;
+
+ chan->drm.fb_ctxdma_handle = fb_ctxdma;
+ chan->drm.tt_ctxdma_handle = tt_ctxdma;
+ ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
+ &chan->drm, sizeof(chan->drm));
+ if (ret) {
+ free(chan);
+ return ret;
+ }
+
+ chan->base.id = chan->drm.channel;
+ if (nouveau_grobj_ref(&chan->base, chan->drm.fb_ctxdma_handle,
+ &chan->base.vram) ||
+ nouveau_grobj_ref(&chan->base, chan->drm.tt_ctxdma_handle,
+ &chan->base.gart)) {
+ nouveau_channel_free((void *)&chan);
+ return -EINVAL;
+ }
+
+ ret = drmMap(nv->fd, chan->drm.ctrl, chan->drm.ctrl_size,
+ (void*)&chan->user);
+ if (ret) {
+ nouveau_channel_free((void *)&chan);
+ return ret;
+ }
+ chan->put = &chan->user[0x40/4];
+ chan->get = &chan->user[0x44/4];
+ chan->ref_cnt = &chan->user[0x48/4];
+
+ ret = drmMap(nv->fd, chan->drm.notifier, chan->drm.notifier_size,
+ (drmAddressPtr)&chan->notifier_block);
+ if (ret) {
+ nouveau_channel_free((void *)&chan);
+ return ret;
+ }
+
+ ret = drmMap(nv->fd, chan->drm.cmdbuf, chan->drm.cmdbuf_size,
+ (void*)&chan->pushbuf);
+ if (ret) {
+ nouveau_channel_free((void *)&chan);
+ return ret;
+ }
+
+ nouveau_dma_channel_init(&chan->base);
+ nouveau_pushbuf_init(&chan->base);
+
+ *userchan = &chan->base;
+ return 0;
+}
+
+void
+nouveau_channel_free(struct nouveau_channel **userchan)
+{
+ struct nouveau_channel_priv *chan;
+
+ if (!userchan)
+ return;
+ chan = nouveau_channel(*userchan);
+
+ if (chan) {
+ struct nouveau_device_priv *nv;
+ struct drm_nouveau_channel_free cf;
+
+ nv = nouveau_device((*userchan)->device);
+ *userchan = NULL;
+
+ FIRE_RING_CH(&chan->base);
+
+ nouveau_grobj_free(&chan->base.vram);
+ nouveau_grobj_free(&chan->base.gart);
+
+ cf.channel = chan->drm.channel;
+ drmCommandWrite(nv->fd, DRM_NOUVEAU_CHANNEL_FREE,
+ &cf, sizeof(cf));
+ free(chan);
+ }
+}
+
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c
new file mode 100644
index 0000000000..03f1816c32
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.c
@@ -0,0 +1,250 @@
+#include "main/glheader.h"
+#include "glapi/glthread.h"
+#include <GL/internal/glcore.h>
+
+#include "state_tracker/st_public.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_context.h"
+
+#include "nouveau_context.h"
+#include "nouveau_dri.h"
+#include "nouveau_local.h"
+#include "nouveau_screen.h"
+#include "nouveau_winsys_pipe.h"
+
+#define need_GL_ARB_fragment_program
+#define need_GL_ARB_multisample
+#define need_GL_ARB_occlusion_query
+#define need_GL_ARB_point_parameters
+#define need_GL_ARB_texture_compression
+#define need_GL_ARB_vertex_program
+#define need_GL_ARB_vertex_buffer_object
+#define need_GL_EXT_compiled_vertex_array
+#define need_GL_EXT_fog_coord
+#define need_GL_EXT_secondary_color
+#define need_GL_EXT_framebuffer_object
+#include "extension_helper.h"
+
+const struct dri_extension common_extensions[] =
+{
+ { NULL, 0 }
+};
+
+const struct dri_extension nv40_extensions[] =
+{
+ { "GL_ARB_fragment_program", NULL },
+ { "GL_ARB_multisample", GL_ARB_multisample_functions },
+ { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions },
+ { "GL_ARB_point_parameters", GL_ARB_point_parameters_functions },
+ { "GL_ARB_texture_border_clamp", NULL },
+ { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
+ { "GL_ARB_texture_cube_map", NULL },
+ { "GL_ARB_texture_env_add", NULL },
+ { "GL_ARB_texture_env_combine", NULL },
+ { "GL_ARB_texture_env_crossbar", NULL },
+ { "GL_ARB_texture_env_dot3", NULL },
+ { "GL_ARB_texture_mirrored_repeat", NULL },
+ { "GL_ARB_texture_non_power_of_two", NULL },
+ { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
+ { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
+ { "GL_ATI_texture_env_combine3", NULL },
+ { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
+ { "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
+ { "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions },
+ { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
+ { "GL_EXT_texture_edge_clamp", NULL },
+ { "GL_EXT_texture_env_add", NULL },
+ { "GL_EXT_texture_env_combine", NULL },
+ { "GL_EXT_texture_env_dot3", NULL },
+ { "GL_EXT_texture_mirror_clamp", NULL },
+ { "GL_NV_texture_rectangle", NULL },
+ { NULL, 0 }
+};
+
+#ifdef DEBUG
+static const struct dri_debug_control debug_control[] = {
+ { "bo", DEBUG_BO },
+ { NULL, 0 }
+};
+int __nouveau_debug = 0;
+#endif
+
+GLboolean
+nouveau_context_create(const __GLcontextModes *glVis,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate)
+{
+ __DRIscreenPrivate *driScrnPriv = driContextPriv->driScreenPriv;
+ struct nouveau_screen *nv_screen = driScrnPriv->private;
+ struct nouveau_context *nv = CALLOC_STRUCT(nouveau_context);
+ struct nouveau_device_priv *nvdev;
+ struct pipe_context *pipe = NULL;
+ struct st_context *st_share = NULL;
+ int ret;
+
+ if (sharedContextPrivate) {
+ st_share = ((struct nouveau_context *)sharedContextPrivate)->st;
+ }
+
+ if ((ret = nouveau_device_get_param(nv_screen->device,
+ NOUVEAU_GETPARAM_CHIPSET_ID,
+ &nv->chipset))) {
+ NOUVEAU_ERR("Error determining chipset id: %d\n", ret);
+ return GL_FALSE;
+ }
+
+ if ((ret = nouveau_channel_alloc(nv_screen->device,
+ 0x8003d001, 0x8003d002,
+ &nv->channel))) {
+ NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
+ return GL_FALSE;
+ }
+
+ driContextPriv->driverPrivate = (void *)nv;
+ nv->nv_screen = nv_screen;
+ nv->dri_screen = driScrnPriv;
+
+ nvdev = nouveau_device(nv_screen->device);
+ nvdev->ctx = driContextPriv->hHWContext;
+ nvdev->lock = (drmLock *)&driScrnPriv->pSAREA->lock;
+
+ driParseConfigFiles(&nv->dri_option_cache, &nv_screen->option_cache,
+ nv->dri_screen->myNum, "nouveau");
+#ifdef DEBUG
+ __nouveau_debug = driParseDebugString(getenv("NOUVEAU_DEBUG"),
+ debug_control);
+#endif
+
+ /*XXX: Hack up a fake region and buffer object for front buffer.
+ * This will go away with TTM, replaced with a simple reference
+ * of the front buffer handle passed to us by the DDX.
+ */
+ {
+ struct pipe_surface *fb_surf;
+ struct nouveau_bo_priv *fb_bo;
+
+ fb_bo = calloc(1, sizeof(struct nouveau_bo_priv));
+ fb_bo->drm.offset = nv_screen->front_offset;
+ fb_bo->drm.flags = NOUVEAU_MEM_FB;
+ fb_bo->drm.size = nv_screen->front_pitch *
+ nv_screen->front_height;
+ fb_bo->refcount = 1;
+ fb_bo->base.flags = NOUVEAU_BO_PIN | NOUVEAU_BO_VRAM;
+ fb_bo->base.offset = fb_bo->drm.offset;
+ fb_bo->base.handle = (unsigned long)fb_bo;
+ fb_bo->base.size = fb_bo->drm.size;
+ fb_bo->base.device = nv_screen->device;
+
+ fb_surf = calloc(1, sizeof(struct pipe_surface));
+ fb_surf->cpp = nv_screen->front_cpp;
+ fb_surf->pitch = nv_screen->front_pitch / fb_surf->cpp;
+ fb_surf->height = nv_screen->front_height;
+ fb_surf->refcount = 1;
+ fb_surf->buffer = (void *)fb_bo;
+
+ nv->frontbuffer = fb_surf;
+ }
+
+ if ((ret = nouveau_grobj_alloc(nv->channel, 0x00000000, 0x30,
+ &nv->NvNull))) {
+ NOUVEAU_ERR("Error creating NULL object: %d\n", ret);
+ return GL_FALSE;
+ }
+ nv->next_handle = 0x80000000;
+
+ if ((ret = nouveau_notifier_alloc(nv->channel, nv->next_handle++, 1,
+ &nv->sync_notifier))) {
+ NOUVEAU_ERR("Error creating channel sync notifier: %d\n", ret);
+ return GL_FALSE;
+ }
+
+ if (nv->chipset < 0x50)
+ ret = nouveau_surface_init_nv04(nv);
+ else
+ ret = nouveau_surface_init_nv50(nv);
+ if (ret) {
+ return GL_FALSE;
+ }
+
+ if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
+ pipe = nouveau_pipe_create(nv);
+ if (!pipe)
+ NOUVEAU_ERR("Couldn't create hw pipe\n");
+ }
+
+ if (!pipe) {
+ NOUVEAU_MSG("Using softpipe\n");
+ pipe = nouveau_create_softpipe(nv);
+ if (!pipe) {
+ NOUVEAU_ERR("Error creating pipe, bailing\n");
+ return GL_FALSE;
+ }
+ }
+
+ pipe->priv = nv;
+ nv->st = st_create_context(pipe, glVis, st_share);
+ return GL_TRUE;
+}
+
+void
+nouveau_context_destroy(__DRIcontextPrivate *driContextPriv)
+{
+ struct nouveau_context *nv = driContextPriv->driverPrivate;
+
+ assert(nv);
+
+ st_flush(nv->st, PIPE_FLUSH_WAIT);
+ st_destroy_context(nv->st);
+
+ nouveau_grobj_free(&nv->NvCtxSurf2D);
+ nouveau_grobj_free(&nv->NvImageBlit);
+ nouveau_channel_free(&nv->channel);
+
+ free(nv);
+}
+
+GLboolean
+nouveau_context_bind(__DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv)
+{
+ struct nouveau_context *nv;
+ struct nouveau_framebuffer *draw, *read;
+
+ if (!driContextPriv) {
+ st_make_current(NULL, NULL, NULL);
+ return GL_TRUE;
+ }
+
+ nv = driContextPriv->driverPrivate;
+ draw = driDrawPriv->driverPrivate;
+ read = driReadPriv->driverPrivate;
+
+ st_make_current(nv->st, draw->stfb, read->stfb);
+
+ if ((nv->dri_drawable != driDrawPriv) ||
+ (nv->last_stamp != driDrawPriv->lastStamp)) {
+ nv->dri_drawable = driDrawPriv;
+ st_resize_framebuffer(draw->stfb, driDrawPriv->w,
+ driDrawPriv->h);
+ nv->last_stamp = driDrawPriv->lastStamp;
+ }
+
+ if (driDrawPriv != driReadPriv) {
+ st_resize_framebuffer(read->stfb, driReadPriv->w,
+ driReadPriv->h);
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean
+nouveau_context_unbind(__DRIcontextPrivate *driContextPriv)
+{
+ struct nouveau_context *nv = driContextPriv->driverPrivate;
+ (void)nv;
+
+ st_flush(nv->st, 0);
+ return GL_TRUE;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
new file mode 100644
index 0000000000..cd59b7cc43
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
@@ -0,0 +1,105 @@
+#ifndef __NOUVEAU_CONTEXT_H__
+#define __NOUVEAU_CONTEXT_H__
+
+#include "dri_util.h"
+#include "xmlconfig.h"
+
+#include "pipe/nouveau/nouveau_winsys.h"
+#include "nouveau_device.h"
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+
+struct nouveau_framebuffer {
+ struct st_framebuffer *stfb;
+};
+
+struct nouveau_context {
+ struct st_context *st;
+
+ /* Misc HW info */
+ uint64_t chipset;
+
+ /* DRI stuff */
+ __DRIscreenPrivate *dri_screen;
+ __DRIdrawablePrivate *dri_drawable;
+ unsigned int last_stamp;
+ driOptionCache dri_option_cache;
+ drm_context_t drm_context;
+ drmLock drm_lock;
+ GLboolean locked;
+ struct nouveau_screen *nv_screen;
+ struct pipe_surface *frontbuffer;
+
+ /* Bufmgr */
+ struct {
+ struct nouveau_channel *channel;
+ struct nouveau_notifier *notify;
+ struct nouveau_grobj *m2mf;
+ uint32_t m2mf_src_ctxdma;
+ uint32_t m2mf_dst_ctxdma;
+ uint32_t next_sequence;
+ } bo;
+
+ /* Relocations */
+ struct nouveau_bo *reloc_head;
+
+ /* Hardware context */
+ uint32_t *pushbuf;
+ struct nouveau_channel *channel;
+ struct nouveau_notifier *sync_notifier;
+ struct nouveau_grobj *NvNull;
+ struct nouveau_grobj *NvCtxSurf2D;
+ struct nouveau_grobj *NvImageBlit;
+ struct nouveau_grobj *NvGdiRect;
+ struct nouveau_grobj *NvM2MF;
+ struct nouveau_grobj *Nv2D;
+ uint32_t next_handle;
+ uint32_t next_sequence;
+
+ /* pipe_surface accel */
+ struct pipe_surface *surf_src, *surf_dst;
+ unsigned surf_src_offset, surf_dst_offset;
+ int (*surface_copy_prep)(struct nouveau_context *,
+ struct pipe_surface *dst,
+ struct pipe_surface *src);
+ void (*surface_copy)(struct nouveau_context *, unsigned dx, unsigned dy,
+ unsigned sx, unsigned sy, unsigned w, unsigned h);
+ void (*surface_copy_done)(struct nouveau_context *);
+ int (*surface_fill)(struct nouveau_context *, struct pipe_surface *,
+ unsigned, unsigned, unsigned, unsigned, unsigned);
+ int (*surface_data)(struct nouveau_context *, struct pipe_surface *,
+ unsigned, unsigned, const void *, unsigned,
+ unsigned, unsigned, unsigned, unsigned);
+};
+
+extern GLboolean nouveau_context_create(const __GLcontextModes *,
+ __DRIcontextPrivate *, void *);
+extern void nouveau_context_destroy(__DRIcontextPrivate *);
+extern GLboolean nouveau_context_bind(__DRIcontextPrivate *,
+ __DRIdrawablePrivate *draw,
+ __DRIdrawablePrivate *read);
+extern GLboolean nouveau_context_unbind(__DRIcontextPrivate *);
+
+#ifdef DEBUG
+extern int __nouveau_debug;
+
+#define DEBUG_BO (1 << 0)
+
+#define DBG(flag, ...) do { \
+ if (__nouveau_debug & (DEBUG_##flag)) \
+ NOUVEAU_ERR(__VA_ARGS__); \
+} while(0)
+#else
+#define DBG(flag, ...)
+#endif
+
+extern void LOCK_HARDWARE(struct nouveau_context *);
+extern void UNLOCK_HARDWARE(struct nouveau_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 *);
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c
new file mode 100644
index 0000000000..a3f5513550
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+
+int
+nouveau_device_open_existing(struct nouveau_device **userdev, int close,
+ int fd, drm_context_t ctx)
+{
+ struct nouveau_device_priv *nv;
+ int ret;
+
+ if (!userdev || *userdev)
+ return -EINVAL;
+
+ nv = calloc(1, sizeof(*nv));
+ if (!nv)
+ return -ENOMEM;
+ nv->fd = fd;
+ nv->ctx = ctx;
+ nv->needs_close = close;
+
+ drmCommandNone(nv->fd, DRM_NOUVEAU_CARD_INIT);
+
+ if ((ret = nouveau_bo_init(&nv->base))) {
+ nouveau_device_close((void *)&nv);
+ return ret;
+ }
+
+ *userdev = &nv->base;
+ return 0;
+}
+
+int
+nouveau_device_open(struct nouveau_device **userdev, const char *busid)
+{
+ drm_context_t ctx;
+ int fd, ret;
+
+ if (!userdev || *userdev)
+ return -EINVAL;
+
+ fd = drmOpen("nouveau", busid);
+ if (fd < 0)
+ return -EINVAL;
+
+ ret = drmCreateContext(fd, &ctx);
+ if (ret) {
+ drmClose(fd);
+ return ret;
+ }
+
+ ret = nouveau_device_open_existing(userdev, 1, fd, ctx);
+ if (ret) {
+ drmDestroyContext(fd, ctx);
+ drmClose(fd);
+ return ret;
+ }
+
+ return 0;
+}
+
+void
+nouveau_device_close(struct nouveau_device **userdev)
+{
+ struct nouveau_device_priv *nv;
+
+ if (userdev || !*userdev)
+ return;
+ nv = (struct nouveau_device_priv *)*userdev;
+ *userdev = NULL;
+
+ nouveau_bo_takedown(&nv->base);
+
+ if (nv->needs_close) {
+ drmDestroyContext(nv->fd, nv->ctx);
+ drmClose(nv->fd);
+ }
+ free(nv);
+}
+
+int
+nouveau_device_get_param(struct nouveau_device *userdev,
+ uint64_t param, uint64_t *value)
+{
+ struct nouveau_device_priv *nv = (struct nouveau_device_priv *)userdev;
+ struct drm_nouveau_getparam g;
+ int ret;
+
+ if (!nv || !value)
+ return -EINVAL;
+
+ g.param = param;
+ ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_GETPARAM, &g, sizeof(g));
+ if (ret)
+ return ret;
+
+ *value = g.value;
+ return 0;
+}
+
+int
+nouveau_device_set_param(struct nouveau_device *userdev,
+ uint64_t param, uint64_t value)
+{
+ struct nouveau_device_priv *nv = (struct nouveau_device_priv *)userdev;
+ struct drm_nouveau_setparam s;
+ int ret;
+
+ if (!nv)
+ return -EINVAL;
+
+ s.param = param;
+ s.value = value;
+ ret = drmCommandWriteRead(nv->fd, DRM_NOUVEAU_SETPARAM, &s, sizeof(s));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h
new file mode 100644
index 0000000000..744a89f74b
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_device.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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.
+ */
+
+#ifndef __NOUVEAU_DEVICE_H__
+#define __NOUVEAU_DEVICE_H__
+
+struct nouveau_device {
+};
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
new file mode 100644
index 0000000000..5739e0010d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdint.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+#include "nouveau_local.h"
+
+static __inline__ uint32_t
+READ_GET(struct nouveau_channel_priv *nvchan)
+{
+ return ((*nvchan->get - nvchan->dma.base) >> 2);
+}
+
+static __inline__ void
+WRITE_PUT(struct nouveau_channel_priv *nvchan, uint32_t val)
+{
+ uint32_t put = ((val << 2) + nvchan->dma.base);
+ volatile int dum;
+
+ NOUVEAU_DMA_BARRIER;
+ dum = READ_GET(nvchan);
+
+ *nvchan->put = put;
+ nvchan->dma.put = val;
+#ifdef NOUVEAU_DMA_TRACE
+ NOUVEAU_MSG("WRITE_PUT %d/0x%08x\n", nvchan->drm.channel, put);
+#endif
+
+ NOUVEAU_DMA_BARRIER;
+}
+
+void
+nouveau_dma_channel_init(struct nouveau_channel *userchan)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+ int i;
+
+ chan->dma.base = chan->drm.put_base;
+ chan->dma.cur = chan->dma.put = RING_SKIPS;
+ chan->dma.max = (chan->drm.cmdbuf_size >> 2) - 2;
+ chan->dma.free = chan->dma.max - chan->dma.cur;
+
+ for (i = 0; i < RING_SKIPS; i++)
+ chan->pushbuf[i] = 0x00000000;
+}
+
+#define CHECK_TIMEOUT() do { \
+ if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
+ return - EBUSY; \
+} while(0)
+
+#define IN_MASTER_RING(chan, ptr) ((ptr) <= (chan)->dma.max)
+
+int
+nouveau_dma_wait(struct nouveau_channel *userchan, int size)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+ uint32_t get, t_start;
+
+ FIRE_RING_CH(userchan);
+
+ t_start = NOUVEAU_TIME_MSEC();
+ while (chan->dma.free < size) {
+ CHECK_TIMEOUT();
+
+ get = READ_GET(chan);
+ if (!IN_MASTER_RING(chan, get))
+ continue;
+
+ if (chan->dma.put >= get) {
+ chan->dma.free = chan->dma.max - chan->dma.cur;
+
+ if (chan->dma.free < size) {
+#ifdef NOUVEAU_DMA_DEBUG
+ chan->dma.push_free = 1;
+#endif
+ OUT_RING_CH(userchan,
+ 0x20000000 | chan->dma.base);
+ if (get <= RING_SKIPS) {
+ /*corner case - will be idle*/
+ if (chan->dma.put <= RING_SKIPS)
+ WRITE_PUT(chan, RING_SKIPS + 1);
+
+ do {
+ CHECK_TIMEOUT();
+ get = READ_GET(chan);
+ if (!IN_MASTER_RING(chan, get))
+ continue;
+ } while (get <= RING_SKIPS);
+ }
+
+ WRITE_PUT(chan, RING_SKIPS);
+ chan->dma.cur = chan->dma.put = RING_SKIPS;
+ chan->dma.free = get - (RING_SKIPS + 1);
+ }
+ } else {
+ chan->dma.free = get - chan->dma.cur - 1;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef NOUVEAU_DMA_SUBCHAN_LRU
+void
+nouveau_dma_subc_bind(struct nouveau_grobj *grobj)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(grobj->channel);
+ int subc = -1, i;
+
+ for (i = 0; i < 8; i++) {
+ if (chan->subchannel[i].grobj &&
+ chan->subchannel[i].grobj->bound ==
+ NOUVEAU_GROBJ_EXPLICIT_BIND)
+ continue;
+ if (chan->subchannel[i].seq < chan->subchannel[subc].seq)
+ subc = i;
+ }
+ assert(subc >= 0);
+
+ if (chan->subchannel[subc].grobj)
+ chan->subchannel[subc].grobj->bound = 0;
+ chan->subchannel[subc].grobj = grobj;
+ grobj->subc = subc;
+ grobj->bound = NOUVEAU_GROBJ_BOUND;
+
+ BEGIN_RING_CH(grobj->channel, grobj, 0, 1);
+ nouveau_dma_out (grobj->channel, grobj->handle);
+}
+#endif
+
+void
+nouveau_dma_kickoff(struct nouveau_channel *userchan)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+
+ if (chan->dma.cur == chan->dma.put)
+ return;
+
+#ifdef NOUVEAU_DMA_DEBUG
+ if (chan->dma.push_free) {
+ NOUVEAU_ERR("Packet incomplete: %d left\n", chan->dma.push_free);
+ return;
+ }
+#endif
+
+#ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
+ for (i = chan->dma.put; i < chan->dma.cur; i++) {
+ NOUVEAU_MSG("0x%08x 0x%08x\n", (i<<2)+chan->dma.base,
+ chan->pushbuf[i]);
+ if ((chan->pushbuf[i] & 0xf0000000) == 0x20000000) {
+ int n = (((chan->pushbuf[i] & 0x0fffffff) -
+ chan->dma.base) / 4);
+ do {
+ NOUVEAU_MSG("\t0x%08x 0x%08x\n",
+ (n<<2)+chan->dma.base,
+ chan->pushbuf[n]);
+ } while ((chan->pushbuf[n++]&0xf0000000) != 0x20000000);
+ }
+ }
+#endif
+
+ WRITE_PUT(chan, chan->dma.cur);
+}
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h
new file mode 100644
index 0000000000..927841c4eb
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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.
+ */
+
+#ifndef __NOUVEAU_DMA_H__
+#define __NOUVEAU_DMA_H__
+
+#include <string.h>
+#include "nouveau_drmif.h"
+#include "nouveau_local.h"
+
+#define RING_SKIPS 8
+
+extern int nouveau_dma_wait(struct nouveau_channel *chan, int size);
+extern void nouveau_dma_subc_bind(struct nouveau_grobj *);
+extern void nouveau_dma_channel_init(struct nouveau_channel *);
+extern void nouveau_dma_kickoff(struct nouveau_channel *);
+
+#ifdef NOUVEAU_DMA_DEBUG
+static char faulty[1024];
+#endif
+
+static inline void
+nouveau_dma_out(struct nouveau_channel *userchan, uint32_t data)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+
+#ifdef NOUVEAU_DMA_DEBUG
+ if (chan->dma.push_free == 0) {
+ NOUVEAU_ERR("No space left in packet. Error at %s\n",faulty);
+ return;
+ }
+ chan->dma.push_free--;
+#endif
+#ifdef NOUVEAU_DMA_TRACE
+ {
+ uint32_t offset = (chan->dma.cur << 2) + chan->dma.base;
+ NOUVEAU_MSG("\tOUT_RING %d/0x%08x -> 0x%08x\n",
+ chan->drm.channel, offset, data);
+ }
+#endif
+ chan->pushbuf[chan->dma.cur++] = data;
+}
+
+static inline void
+nouveau_dma_outp(struct nouveau_channel *userchan, uint32_t *ptr, int size)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+ (void)chan;
+
+#ifdef NOUVEAU_DMA_DEBUG
+ if (chan->dma.push_free < size) {
+ NOUVEAU_ERR("Packet too small. Free=%d, Need=%d\n",
+ chan->dma.push_free, size);
+ return;
+ }
+#endif
+#ifdef NOUVEAU_DMA_TRACE
+ while (size--) {
+ nouveau_dma_out(userchan, *ptr);
+ ptr++;
+ }
+#else
+ memcpy(&chan->pushbuf[chan->dma.cur], ptr, size << 2);
+#ifdef NOUVEAU_DMA_DEBUG
+ chan->dma.push_free -= size;
+#endif
+ chan->dma.cur += size;
+#endif
+}
+
+static inline void
+nouveau_dma_begin(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
+ int method, int size, const char* file, int line)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+ int push_size = size + 1;
+
+#ifdef NOUVEAU_DMA_SUBCHAN_LRU
+ if (grobj->bound == NOUVEAU_GROBJ_UNBOUND)
+ nouveau_dma_subc_bind(grobj);
+ chan->subchannel[grobj->subc].seq = chan->subc_sequence++;
+#endif
+
+#ifdef NOUVEAU_DMA_TRACE
+ NOUVEAU_MSG("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", chan->drm.channel,
+ grobj->handle, grobj->subc, method, size);
+#endif
+
+#ifdef NOUVEAU_DMA_DEBUG
+ if (chan->dma.push_free) {
+ NOUVEAU_ERR("Previous packet incomplete: %d left. Error at %s\n",
+ chan->dma.push_free,faulty);
+ return;
+ }
+ sprintf(faulty,"%s:%d",file,line);
+#endif
+
+ if (chan->dma.free < push_size) {
+ if (nouveau_dma_wait(userchan, push_size) &&
+ userchan->hang_notify) {
+ userchan->hang_notify(userchan);
+ }
+ }
+ chan->dma.free -= push_size;
+#ifdef NOUVEAU_DMA_DEBUG
+ chan->dma.push_free = push_size;
+#endif
+
+ nouveau_dma_out(userchan, (size << 18) | (grobj->subc << 13) | method);
+}
+
+static inline void
+nouveau_dma_bind(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
+ int subc)
+{
+ struct nouveau_channel_priv *chan = nouveau_channel(userchan);
+
+ if (chan->subchannel[subc].grobj == grobj)
+ return;
+
+ if (chan->subchannel[subc].grobj)
+ chan->subchannel[subc].grobj->bound = NOUVEAU_GROBJ_UNBOUND;
+ chan->subchannel[subc].grobj = grobj;
+ grobj->subc = subc;
+ grobj->bound = NOUVEAU_GROBJ_EXPLICIT_BIND;
+
+ nouveau_dma_begin(userchan, grobj, 0x0000, 1, __FUNCTION__, __LINE__);
+ nouveau_dma_out (userchan, grobj->handle);
+}
+
+#define BIND_RING_CH(ch,gr,sc) nouveau_dma_bind((ch), (gr), (sc))
+#define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
+#define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
+#define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
+ (dwords))
+#define FIRE_RING_CH(ch) nouveau_dma_kickoff((ch))
+#define WAIT_RING_CH(ch,sz) nouveau_dma_wait((ch), (sz))
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h
new file mode 100644
index 0000000000..1207c2d609
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dri.h
@@ -0,0 +1,28 @@
+#ifndef _NOUVEAU_DRI_
+#define _NOUVEAU_DRI_
+
+#include "xf86drm.h"
+#include "drm.h"
+#include "nouveau_drm.h"
+
+struct nouveau_dri {
+ uint32_t device_id; /**< \brief PCI device ID */
+ uint32_t width; /**< \brief width in pixels of display */
+ uint32_t height; /**< \brief height in scanlines of display */
+ uint32_t depth; /**< \brief depth of display (8, 15, 16, 24) */
+ uint32_t bpp; /**< \brief bit depth of display (8, 16, 24, 32) */
+
+ uint32_t bus_type; /**< \brief ths bus type */
+ uint32_t bus_mode; /**< \brief bus mode (used for AGP, maybe also for PCI-E ?) */
+
+ uint32_t front_offset; /**< \brief front buffer offset */
+ uint32_t front_pitch; /**< \brief front buffer pitch */
+ uint32_t back_offset; /**< \brief private back buffer offset */
+ uint32_t back_pitch; /**< \brief private back buffer pitch */
+ uint32_t depth_offset; /**< \brief private depth buffer offset */
+ uint32_t depth_pitch; /**< \brief private depth buffer pitch */
+
+};
+
+#endif
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
new file mode 100644
index 0000000000..6d6633fac3
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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.
+ */
+
+#ifndef __NOUVEAU_DRMIF_H__
+#define __NOUVEAU_DRMIF_H__
+
+#include <stdint.h>
+#include <xf86drm.h>
+#include <nouveau_drm.h>
+
+#include "nouveau_device.h"
+#include "pipe/nouveau/nouveau_channel.h"
+#include "pipe/nouveau/nouveau_grobj.h"
+#include "pipe/nouveau/nouveau_notifier.h"
+#include "pipe/nouveau/nouveau_bo.h"
+#include "pipe/nouveau/nouveau_resource.h"
+
+struct nouveau_device_priv {
+ struct nouveau_device base;
+
+ int fd;
+ drm_context_t ctx;
+ drmLock *lock;
+ int needs_close;
+};
+#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
+
+extern int
+nouveau_device_open_existing(struct nouveau_device **, int close,
+ int fd, drm_context_t ctx);
+
+extern int
+nouveau_device_open(struct nouveau_device **, const char *busid);
+
+extern void
+nouveau_device_close(struct nouveau_device **);
+
+extern int
+nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
+
+extern int
+nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
+
+struct nouveau_fence {
+ struct nouveau_channel *channel;
+};
+
+struct nouveau_fence_cb {
+ struct nouveau_fence_cb *next;
+ void (*func)(void *);
+ void *priv;
+};
+
+struct nouveau_fence_priv {
+ struct nouveau_fence base;
+ int refcount;
+
+ struct nouveau_fence *next;
+ struct nouveau_fence_cb *signal_cb;
+
+ uint32_t sequence;
+ int emitted;
+ int signalled;
+};
+#define nouveau_fence(n) ((struct nouveau_fence_priv *)(n))
+
+extern int
+nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **);
+
+extern int
+nouveau_fence_ref(struct nouveau_fence *, struct nouveau_fence **);
+
+extern void
+nouveau_fence_del(struct nouveau_fence **);
+
+extern int
+nouveau_fence_signal_cb(struct nouveau_fence *, void (*)(void *), void *);
+extern void
+nouveau_fence_emit(struct nouveau_fence *);
+
+extern int
+nouveau_fence_wait(struct nouveau_fence **);
+
+extern void
+nouveau_fence_flush(struct nouveau_channel *);
+
+struct nouveau_pushbuf_reloc {
+ uint64_t next;
+ uint64_t handle;
+ uint32_t *ptr;
+ uint32_t flags;
+ uint32_t data;
+ uint32_t vor;
+ uint32_t tor;
+};
+
+struct nouveau_pushbuf_bo {
+ uint64_t next;
+ uint64_t handle;
+ uint64_t flags;
+ uint64_t relocs;
+ int nr_relocs;
+};
+
+struct nouveau_pushbuf {
+ struct nouveau_channel *channel;
+ unsigned remaining;
+ uint32_t *cur;
+};
+
+struct nouveau_pushbuf_priv {
+ struct nouveau_pushbuf base;
+ struct nouveau_pushbuf *next;
+
+ struct nouveau_resource *res;
+ struct nouveau_fence *fence;
+
+ uint64_t buffers;
+ int nr_buffers;
+};
+#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+#define pbbo_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_pbbo(h) ((struct nouveau_pushbuf_bo *)(unsigned long)(h))
+#define pbrel_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_pbrel(h) ((struct nouveau_pushbuf_reloc *)(unsigned long)(h))
+#define bo_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_bo(h) ((struct nouveau_bo_priv *)(unsigned long)(h))
+
+extern int
+nouveau_pushbuf_init(struct nouveau_channel *);
+
+extern int
+nouveau_pushbuf_flush(struct nouveau_channel *);
+
+extern int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
+ struct nouveau_bo *, uint32_t data, uint32_t flags,
+ uint32_t vor, uint32_t tor);
+
+struct nouveau_channel_priv {
+ struct nouveau_channel base;
+
+ struct drm_nouveau_channel_alloc drm;
+
+ struct {
+ struct nouveau_grobj *grobj;
+ uint32_t seq;
+ } subchannel[8];
+ uint32_t subc_sequence;
+
+ uint32_t *pushbuf;
+ void *notifier_block;
+
+ volatile uint32_t *user;
+ volatile uint32_t *put;
+ volatile uint32_t *get;
+ volatile uint32_t *ref_cnt;
+
+ struct {
+ uint32_t base, max;
+ uint32_t cur, put;
+ uint32_t free;
+
+ int push_free;
+ } dma;
+
+ struct nouveau_fence *fence_head;
+ struct nouveau_fence *fence_tail;
+ uint32_t fence_sequence;
+
+ struct nouveau_resource *pb_heap;
+ struct nouveau_pushbuf *pb_head;
+ struct nouveau_pushbuf *pb_tail;
+};
+#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
+
+extern int
+nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
+ struct nouveau_channel **);
+
+extern void
+nouveau_channel_free(struct nouveau_channel **);
+
+struct nouveau_grobj_priv {
+ struct nouveau_grobj base;
+};
+#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
+
+extern int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
+ int class, struct nouveau_grobj **);
+extern int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
+ struct nouveau_grobj **);
+extern void nouveau_grobj_free(struct nouveau_grobj **);
+
+
+struct nouveau_notifier_priv {
+ struct nouveau_notifier base;
+
+ struct drm_nouveau_notifierobj_alloc drm;
+ volatile void *map;
+};
+#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
+
+extern int
+nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
+ struct nouveau_notifier **);
+
+extern void
+nouveau_notifier_free(struct nouveau_notifier **);
+
+extern void
+nouveau_notifier_reset(struct nouveau_notifier *, int id);
+
+extern uint32_t
+nouveau_notifier_status(struct nouveau_notifier *, int id);
+
+extern uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *, int id);
+
+extern int
+nouveau_notifier_wait_status(struct nouveau_notifier *, int id, int status,
+ int timeout);
+
+struct nouveau_bo_priv {
+ struct nouveau_bo base;
+
+ struct nouveau_fence *fence;
+
+ struct drm_nouveau_mem_alloc drm;
+ void *map;
+
+ void *sysmem;
+ int user;
+
+ int refcount;
+ int sync_hack;
+};
+#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
+
+extern int
+nouveau_bo_init(struct nouveau_device *);
+
+extern void
+nouveau_bo_takedown(struct nouveau_device *);
+
+extern int
+nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
+ struct nouveau_bo **);
+
+extern int
+nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
+ struct nouveau_bo **);
+
+extern int
+nouveau_bo_ref(struct nouveau_device *, uint64_t handle, struct nouveau_bo **);
+
+extern int
+nouveau_bo_resize(struct nouveau_bo *, int size);
+
+extern void
+nouveau_bo_del(struct nouveau_bo **);
+
+extern int
+nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
+
+extern void
+nouveau_bo_unmap(struct nouveau_bo *);
+
+extern int
+nouveau_bo_validate(struct nouveau_channel *, struct nouveau_bo *,
+ struct nouveau_fence *fence, uint32_t flags);
+
+extern int
+nouveau_resource_init(struct nouveau_resource **heap, unsigned start,
+ unsigned size);
+
+extern int
+nouveau_resource_alloc(struct nouveau_resource *heap, int size, void *priv,
+ struct nouveau_resource **);
+
+extern void
+nouveau_resource_free(struct nouveau_resource **);
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c
new file mode 100644
index 0000000000..7861b6f84d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+#include "nouveau_local.h"
+
+int
+nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **fence)
+{
+ struct nouveau_fence_priv *nvfence;
+
+ if (!chan || !fence || *fence)
+ return -EINVAL;
+
+ nvfence = calloc(1, sizeof(struct nouveau_fence_priv));
+ if (!nvfence)
+ return -ENOMEM;
+ nvfence->base.channel = chan;
+ nvfence->refcount = 1;
+
+ *fence = &nvfence->base;
+ return 0;
+}
+
+int
+nouveau_fence_ref(struct nouveau_fence *ref, struct nouveau_fence **fence)
+{
+ struct nouveau_fence_priv *nvfence;
+
+ if (!ref || !fence || *fence)
+ return -EINVAL;
+ nvfence = nouveau_fence(ref);
+ nvfence->refcount++;
+
+ *fence = &nvfence->base;
+ return 0;
+}
+
+void
+nouveau_fence_del(struct nouveau_fence **fence)
+{
+ struct nouveau_fence_priv *nvfence;
+
+ if (!fence || !*fence)
+ return;
+ nvfence = nouveau_fence(*fence);
+ *fence = NULL;
+
+ if (--nvfence->refcount <= 0) {
+ if (nvfence->emitted && !nvfence->signalled)
+ nouveau_fence_wait((void *)&nvfence);
+ free(nvfence);
+ }
+}
+
+int
+nouveau_fence_signal_cb(struct nouveau_fence *fence, void (*func)(void *),
+ void *priv)
+{
+ struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
+ struct nouveau_fence_cb *cb;
+
+ if (!nvfence || !func)
+ return -EINVAL;
+
+ cb = malloc(sizeof(struct nouveau_fence_cb));
+ if (!cb)
+ return -ENOMEM;
+
+ cb->func = func;
+ cb->priv = priv;
+ cb->next = nvfence->signal_cb;
+ nvfence->signal_cb = cb;
+ return 0;
+}
+
+void
+nouveau_fence_emit(struct nouveau_fence *fence)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(fence->channel);
+ struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
+
+ nvfence->emitted = 1;
+ nvfence->sequence = ++nvchan->fence_sequence;
+ if (nvfence->sequence == 0xffffffff)
+ NOUVEAU_ERR("AII wrap unhandled\n");
+
+ BEGIN_RING_CH(&nvchan->base, nvchan->subchannel[0].grobj, 0x50, 1);
+ OUT_RING_CH (&nvchan->base, nvfence->sequence);
+
+ if (nvchan->fence_tail) {
+ nouveau_fence(nvchan->fence_tail)->next = fence;
+ } else {
+ nvchan->fence_head = fence;
+ }
+ nvchan->fence_tail = fence;
+}
+
+void
+nouveau_fence_flush(struct nouveau_channel *chan)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+ uint32_t sequence = *nvchan->ref_cnt;
+
+ while (nvchan->fence_head) {
+ struct nouveau_fence *fence = NULL;
+ struct nouveau_fence_priv *nvfence;
+
+ nouveau_fence_ref(nvchan->fence_head, &fence);
+ nvfence = nouveau_fence(nvchan->fence_head);
+
+ if (nvfence->sequence > sequence) {
+ nouveau_fence_del(&fence);
+ break;
+ }
+
+ nvchan->fence_head = nvfence->next;
+ if (nvchan->fence_head == NULL)
+ nvchan->fence_tail = NULL;
+ nvfence->signalled = 1;
+
+ while (nvfence->signal_cb) {
+ struct nouveau_fence_cb *cb = nvfence->signal_cb;
+ nvfence->signal_cb = cb->next;
+ cb->func(cb->priv);
+ free(cb);
+ }
+
+ nouveau_fence_del(&fence);
+ }
+}
+
+int
+nouveau_fence_wait(struct nouveau_fence **fence)
+{
+ struct nouveau_fence_priv *nvfence;
+
+ if (!fence || !*fence)
+ return -EINVAL;
+ nvfence = nouveau_fence(*fence);
+
+ if (nvfence->emitted) {
+ while (!nvfence->signalled)
+ nouveau_fence_flush(nvfence->base.channel);
+ }
+ nouveau_fence_del(fence);
+
+ return 0;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c
new file mode 100644
index 0000000000..8dab202395
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_grobj.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+
+int
+nouveau_grobj_alloc(struct nouveau_channel *userchan, uint32_t handle,
+ int class, struct nouveau_grobj **usergrobj)
+{
+ struct nouveau_device_priv *nv = nouveau_device(userchan->device);
+ struct nouveau_grobj_priv *gr;
+ struct drm_nouveau_grobj_alloc g;
+ int ret;
+
+ if (!nv || !usergrobj || *usergrobj)
+ return -EINVAL;
+
+ gr = calloc(1, sizeof(*gr));
+ if (!gr)
+ return -ENOMEM;
+ gr->base.channel = userchan;
+ gr->base.handle = handle;
+ gr->base.grclass = class;
+
+ g.channel = userchan->id;
+ g.handle = handle;
+ g.class = class;
+ ret = drmCommandWrite(nv->fd, DRM_NOUVEAU_GROBJ_ALLOC, &g, sizeof(g));
+ if (ret) {
+ nouveau_grobj_free((void *)&gr);
+ return ret;
+ }
+
+ *usergrobj = &gr->base;
+ return 0;
+}
+
+int
+nouveau_grobj_ref(struct nouveau_channel *userchan, uint32_t handle,
+ struct nouveau_grobj **usergr)
+{
+ struct nouveau_grobj_priv *gr;
+
+ if (!userchan || !usergr || *usergr)
+ return -EINVAL;
+
+ gr = calloc(1, sizeof(*gr));
+ if (!gr)
+ return -ENOMEM;
+ gr->base.channel = userchan;
+ gr->base.handle = handle;
+ gr->base.grclass = 0;
+
+ *usergr = &gr->base;
+ return 0;
+}
+
+void
+nouveau_grobj_free(struct nouveau_grobj **usergrobj)
+{
+ struct nouveau_grobj_priv *gr;
+
+ if (!usergrobj)
+ return;
+ gr = nouveau_grobj(*usergrobj);
+ *usergrobj = NULL;
+
+ if (gr) {
+ struct nouveau_channel_priv *chan;
+ struct nouveau_device_priv *nv;
+ struct drm_nouveau_gpuobj_free f;
+
+ chan = nouveau_channel(gr->base.channel);
+ nv = nouveau_device(chan->base.device);
+
+ if (gr->base.grclass) {
+ f.channel = chan->drm.channel;
+ f.handle = gr->base.handle;
+ drmCommandWrite(nv->fd, DRM_NOUVEAU_GPUOBJ_FREE,
+ &f, sizeof(f));
+ }
+ free(gr);
+ }
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
new file mode 100644
index 0000000000..1978edea02
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
@@ -0,0 +1,78 @@
+#ifndef __NOUVEAU_LOCAL_H__
+#define __NOUVEAU_LOCAL_H__
+
+#include <stdio.h>
+
+/* Debug output */
+#define NOUVEAU_MSG(fmt, args...) do { \
+ fprintf(stdout, "nouveau: "fmt, ##args); \
+ fflush(stdout); \
+} while(0)
+
+#define NOUVEAU_ERR(fmt, args...) do { \
+ fprintf(stderr, "%s:%d - "fmt, __func__, __LINE__, ##args); \
+ fflush(stderr); \
+} while(0)
+
+#define NOUVEAU_TIME_MSEC() 0
+
+/* User FIFO control */
+//#define NOUVEAU_DMA_TRACE
+//#define NOUVEAU_DMA_DEBUG
+//#define NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
+#define NOUVEAU_DMA_SUBCHAN_LRU
+#define NOUVEAU_DMA_BARRIER
+#define NOUVEAU_DMA_TIMEOUT 2000
+
+/* Push buffer access macros */
+#define BEGIN_RING(obj,mthd,size) do { \
+ nv->pushbuf = nouveau_pipe_dma_beginp(nv->obj, (mthd), (size)); \
+} while(0)
+
+#define OUT_RING(data) do { \
+ (*nv->pushbuf++) = (data); \
+} while(0)
+
+#define OUT_RINGp(src,size) do { \
+ memcpy(nv->pushbuf, (src), (size)<<2); \
+ nv->pushbuf += (size); \
+} while(0)
+
+#define OUT_RINGf(data) do { \
+ union { float v; uint32_t u; } c; \
+ c.v = (data); \
+ OUT_RING(c.u); \
+} while(0)
+
+#define FIRE_RING() do { \
+ nouveau_pipe_dma_kickoff(nv->channel); \
+} while(0)
+
+#define OUT_RELOC(bo,data,flags,vor,tor) do { \
+ nouveau_pushbuf_emit_reloc(nv->channel, nv->pushbuf, (void*)(bo), \
+ (data), (flags), (vor), (tor)); \
+ OUT_RING(0); \
+} while(0)
+
+/* Raw data + flags depending on FB/TT buffer */
+#define OUT_RELOCd(bo,data,flags,vor,tor) do { \
+ OUT_RELOC((bo), (data), (flags) | NOUVEAU_BO_OR, (vor), (tor)); \
+} while(0)
+
+/* FB/TT object handle */
+#define OUT_RELOCo(bo,flags) do { \
+ OUT_RELOC((bo), 0, (flags) | NOUVEAU_BO_OR, \
+ nv->channel->vram->handle, nv->channel->gart->handle); \
+} while(0)
+
+/* Low 32-bits of offset */
+#define OUT_RELOCl(bo,delta,flags) do { \
+ OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_LOW, 0, 0); \
+} while(0)
+
+/* High 32-bits of offset */
+#define OUT_RELOCh(bo,delta,flags) do { \
+ OUT_RELOC((bo), (delta), (flags) | NOUVEAU_BO_HIGH, 0, 0); \
+} while(0)
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c
new file mode 100644
index 0000000000..9adb9ac854
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_lock.c
@@ -0,0 +1,94 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS 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 "main/glheader.h"
+#include "glapi/glthread.h"
+#include <GL/internal/glcore.h>
+
+#include "nouveau_context.h"
+#include "nouveau_screen.h"
+
+_glthread_DECLARE_STATIC_MUTEX( lockMutex );
+
+static void
+nouveau_contended_lock(struct nouveau_context *nv, GLuint flags)
+{
+ __DRIdrawablePrivate *dPriv = nv->dri_drawable;
+ __DRIscreenPrivate *sPriv = nv->dri_screen;
+ struct nouveau_screen *nv_screen = nv->nv_screen;
+ struct nouveau_device *dev = nv_screen->device;
+ struct nouveau_device_priv *nvdev = nouveau_device(dev);
+
+ drmGetLock(nvdev->fd, nvdev->ctx, flags);
+
+ /* If the window moved, may need to set a new cliprect now.
+ *
+ * NOTE: This releases and regains the hw lock, so all state
+ * checking must be done *after* this call:
+ */
+ if (dPriv)
+ DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
+}
+
+/* Lock the hardware and validate our state.
+ */
+void
+LOCK_HARDWARE(struct nouveau_context *nv)
+{
+ struct nouveau_screen *nv_screen = nv->nv_screen;
+ struct nouveau_device *dev = nv_screen->device;
+ struct nouveau_device_priv *nvdev = nouveau_device(dev);
+ char __ret=0;
+
+ _glthread_LOCK_MUTEX(lockMutex);
+ assert(!nv->locked);
+
+ DRM_CAS(nvdev->lock, nvdev->ctx,
+ (DRM_LOCK_HELD | nvdev->ctx), __ret);
+
+ if (__ret)
+ nouveau_contended_lock(nv, 0);
+ nv->locked = GL_TRUE;
+}
+
+
+ /* Unlock the hardware using the global current context
+ */
+void
+UNLOCK_HARDWARE(struct nouveau_context *nv)
+{
+ struct nouveau_screen *nv_screen = nv->nv_screen;
+ struct nouveau_device *dev = nv_screen->device;
+ struct nouveau_device_priv *nvdev = nouveau_device(dev);
+
+ assert(nv->locked);
+ nv->locked = GL_FALSE;
+
+ DRM_UNLOCK(nvdev->fd, nvdev->lock, nvdev->ctx);
+
+ _glthread_UNLOCK_MUTEX(lockMutex);
+}
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c
new file mode 100644
index 0000000000..e423d59b1d
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_notifier.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_local.h"
+
+#define NOTIFIER(__v) \
+ struct nouveau_notifier_priv *notifier = nouveau_notifier(user); \
+ volatile uint32_t *n = (void*)notifier->map + (id * 32)
+
+int
+nouveau_notifier_alloc(struct nouveau_channel *userchan, uint32_t handle,
+ int count, struct nouveau_notifier **usernotifier)
+{
+ struct nouveau_notifier_priv *notifier;
+ int ret;
+
+ if (!userchan || !usernotifier || *usernotifier)
+ return -EINVAL;
+
+ notifier = calloc(1, sizeof(*notifier));
+ if (!notifier)
+ return -ENOMEM;
+ notifier->base.channel = userchan;
+ notifier->base.handle = handle;
+
+ notifier->drm.channel = userchan->id;
+ notifier->drm.handle = handle;
+ notifier->drm.count = count;
+ if ((ret = drmCommandWriteRead(nouveau_device(userchan->device)->fd,
+ DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
+ &notifier->drm,
+ sizeof(notifier->drm)))) {
+ nouveau_notifier_free((void *)&notifier);
+ return ret;
+ }
+
+ notifier->map = (void *)nouveau_channel(userchan)->notifier_block +
+ notifier->drm.offset;
+ *usernotifier = &notifier->base;
+ return 0;
+}
+
+void
+nouveau_notifier_free(struct nouveau_notifier **usernotifier)
+{
+
+ struct nouveau_notifier_priv *notifier;
+
+ if (!usernotifier)
+ return;
+ notifier = nouveau_notifier(*usernotifier);
+ *usernotifier = NULL;
+
+ if (notifier) {
+ struct nouveau_channel_priv *chan;
+ struct nouveau_device_priv *nv;
+ struct drm_nouveau_gpuobj_free f;
+
+ chan = nouveau_channel(notifier->base.channel);
+ nv = nouveau_device(chan->base.device);
+
+ f.channel = chan->drm.channel;
+ f.handle = notifier->base.handle;
+ drmCommandWrite(nv->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));
+ free(notifier);
+ }
+}
+
+void
+nouveau_notifier_reset(struct nouveau_notifier *user, int id)
+{
+ NOTIFIER(n);
+
+ n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
+ n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
+ n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
+ n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
+ NV_NOTIFY_STATE_STATUS_SHIFT);
+}
+
+uint32_t
+nouveau_notifier_status(struct nouveau_notifier *user, int id)
+{
+ NOTIFIER(n);
+
+ return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+}
+
+uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *user, int id)
+{
+ NOTIFIER(n);
+
+ return n[NV_NOTIFY_RETURN_VALUE/4];
+}
+
+int
+nouveau_notifier_wait_status(struct nouveau_notifier *user, int id,
+ int status, int timeout)
+{
+ NOTIFIER(n);
+ uint32_t time = 0, t_start = NOUVEAU_TIME_MSEC();
+
+ while (time <= timeout) {
+ uint32_t v;
+
+ v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+ if (v == status)
+ return 0;
+
+ if (timeout)
+ time = NOUVEAU_TIME_MSEC() - t_start;
+ }
+
+ return -EBUSY;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c
new file mode 100644
index 0000000000..a922300ff5
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *chan)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+
+ if (!nvchan)
+ return -EINVAL;
+
+ /* Everything except first 4KiB of the push buffer is managed by us */
+ if (nouveau_resource_init(&nvchan->pb_heap, 4096,
+ nvchan->drm.cmdbuf_size - 4096))
+ return -EINVAL;
+
+ /* Shrink master ring to 4KiB */
+ assert(nvchan->dma.cur <= (4096/4));
+ nvchan->dma.max = (4096 / 4) - 2;
+ nvchan->dma.free = nvchan->dma.max - nvchan->dma.cur;
+
+ return 0;
+}
+
+static void
+nouveau_pushbuf_fence_signalled(void *priv)
+{
+ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(priv);
+
+ nouveau_fence_del(&nvpb->fence);
+ nouveau_resource_free(&nvpb->res);
+ free(nvpb);
+}
+
+/* This would be our TTM "superioctl" */
+int
+nouveau_pushbuf_flush(struct nouveau_channel *chan)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(nvchan->pb_tail);
+ struct nouveau_pushbuf_bo *pbbo;
+ struct nouveau_fence *fence = NULL;
+ int sync_hack = 0;
+ int ret;
+
+ if (!nvpb)
+ goto out_realloc;
+
+ if (nvpb->base.remaining == nvpb->res->size / 4)
+ return 0;
+ nvchan->pb_tail = NULL;
+
+ ret = nouveau_fence_new(chan, &fence);
+ if (ret)
+ return ret;
+
+ /* Validate buffers + apply relocations */
+ while ((pbbo = ptr_to_pbbo(nvpb->buffers))) {
+ struct nouveau_pushbuf_reloc *r;
+ struct nouveau_bo *bo = &ptr_to_bo(pbbo->handle)->base;
+
+ ret = nouveau_bo_validate(chan, bo, fence, pbbo->flags);
+ assert (ret == 0);
+
+ sync_hack |= nouveau_bo(bo)->sync_hack;
+ nouveau_bo(bo)->sync_hack = 0;
+
+ while ((r = ptr_to_pbrel(pbbo->relocs))) {
+ uint32_t push;
+
+ if (r->flags & NOUVEAU_BO_LOW) {
+ push = bo->offset + r->data;
+ } else
+ if (r->flags & NOUVEAU_BO_HIGH) {
+ push = (bo->offset + r->data) >> 32;
+ } else {
+ push = r->data;
+ }
+
+ if (r->flags & NOUVEAU_BO_OR) {
+ if (bo->flags & NOUVEAU_BO_VRAM)
+ push |= r->vor;
+ else
+ push |= r->tor;
+ }
+
+ *r->ptr = push;
+ pbbo->relocs = r->next;
+ free(r);
+ }
+
+ nvpb->buffers = pbbo->next;
+ free(pbbo);
+ }
+ nvpb->nr_buffers = 0;
+
+ /* Emit JMP to indirect pushbuf */
+ if (nvchan->dma.free < 1)
+ WAIT_RING_CH(chan, 1);
+ nvchan->dma.free -= 1;
+#ifdef NOUVEAU_DMA_DEBUG
+ nvchan->dma.push_free = 1;
+#endif
+ OUT_RING_CH(chan, 0x20000000 | nvpb->res->start);
+
+ /* Add JMP back to master pushbuf from indirect pushbuf */
+ (*nvpb->base.cur++) =
+ 0x20000000 | ((nvchan->dma.cur << 2) + nvchan->dma.base);
+
+ /* Fence */
+ nvpb->fence = fence;
+ nouveau_fence_signal_cb(nvpb->fence, nouveau_pushbuf_fence_signalled,
+ nvpb);
+ nouveau_fence_emit(nvpb->fence);
+
+ /* Kickoff */
+ FIRE_RING_CH(chan);
+
+ if (sync_hack) {
+ struct nouveau_fence *f = NULL;
+ nouveau_fence_ref(nvpb->fence, &f);
+ nouveau_fence_wait(&f);
+ }
+
+ /* Allocate space for next push buffer */
+out_realloc:
+ nvpb = calloc(1, sizeof(struct nouveau_pushbuf_priv));
+ if (!nvpb)
+ return -ENOMEM;
+
+ while (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, NULL,
+ &nvpb->res)) {
+ nouveau_fence_flush(chan);
+ }
+
+ nvpb->base.channel = chan;
+ nvpb->base.remaining = nvpb->res->size / 4;
+ nvpb->base.cur = &nvchan->pushbuf[nvpb->res->start/4];
+ nvchan->pb_tail = &nvpb->base;
+
+ return 0;
+}
+
+static struct nouveau_pushbuf_bo *
+nouveau_pushbuf_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(nvchan->pb_tail);
+ struct nouveau_pushbuf_bo *pbbo = ptr_to_pbbo(nvpb->buffers);
+
+ while (pbbo) {
+ if (pbbo->handle == bo->handle)
+ return pbbo;
+ pbbo = ptr_to_pbbo(pbbo->next);
+ }
+
+ pbbo = malloc(sizeof(struct nouveau_pushbuf_bo));
+ pbbo->next = nvpb->buffers;
+ nvpb->buffers = pbbo_to_ptr(pbbo);
+ nvpb->nr_buffers++;
+
+ pbbo->handle = bo_to_ptr(bo);
+ pbbo->flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
+ pbbo->relocs = 0;
+ pbbo->nr_relocs = 0;
+ return pbbo;
+}
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
+ struct nouveau_bo *bo, uint32_t data, uint32_t flags,
+ uint32_t vor, uint32_t tor)
+{
+ struct nouveau_pushbuf_bo *pbbo;
+ struct nouveau_pushbuf_reloc *r;
+
+ if (!chan)
+ return -EINVAL;
+
+ pbbo = nouveau_pushbuf_emit_buffer(chan, bo);
+ if (!pbbo)
+ return -EFAULT;
+
+ r = malloc(sizeof(struct nouveau_pushbuf_reloc));
+ r->next = pbbo->relocs;
+ pbbo->relocs = pbrel_to_ptr(r);
+ pbbo->nr_relocs++;
+
+ pbbo->flags |= (flags & NOUVEAU_BO_RDWR);
+ pbbo->flags &= (flags | NOUVEAU_BO_RDWR);
+
+ r->handle = bo_to_ptr(r);
+ r->ptr = ptr;
+ r->flags = flags;
+ r->data = data;
+ r->vor = vor;
+ r->tor = tor;
+
+ return 0;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_resource.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_resource.c
new file mode 100644
index 0000000000..5d9d578b4f
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_resource.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * 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 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 AUTHORS 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 <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_local.h"
+
+int
+nouveau_resource_init(struct nouveau_resource **heap,
+ unsigned start, unsigned size)
+{
+ struct nouveau_resource *r;
+
+ r = calloc(1, sizeof(struct nouveau_resource));
+ if (!r)
+ return 1;
+
+ r->start = start;
+ r->size = size;
+ *heap = r;
+ return 0;
+}
+
+int
+nouveau_resource_alloc(struct nouveau_resource *heap, int size, void *priv,
+ struct nouveau_resource **res)
+{
+ struct nouveau_resource *r;
+
+ if (!heap || !size || !res || *res)
+ return 1;
+
+ while (heap) {
+ if (!heap->in_use && heap->size >= size) {
+ r = calloc(1, sizeof(struct nouveau_resource));
+ if (!r)
+ return 1;
+
+ r->start = (heap->start + heap->size) - size;
+ r->size = size;
+ r->in_use = 1;
+ r->priv = priv;
+
+ heap->size -= size;
+
+ r->next = heap->next;
+ if (heap->next)
+ heap->next->prev = r;
+ r->prev = heap;
+ heap->next = r;
+
+ *res = r;
+ return 0;
+ }
+
+ heap = heap->next;
+ }
+
+ return 1;
+}
+
+void
+nouveau_resource_free(struct nouveau_resource **res)
+{
+ struct nouveau_resource *r;
+
+ if (!res || !*res)
+ return;
+ r = *res;
+
+ if (r->prev && !r->prev->in_use) {
+ r->prev->next = r->next;
+ if (r->next)
+ r->next->prev = r->prev;
+ r->prev->size += r->size;
+ free(r);
+ } else
+ if (r->next && !r->next->in_use) {
+ r->next->prev = r->prev;
+ if (r->prev)
+ r->prev->next = r->next;
+ r->next->size += r->size;
+ r->next->start = r->start;
+ free(r);
+ } else {
+ r->in_use = 0;
+ }
+
+ *res = NULL;
+}
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c
new file mode 100644
index 0000000000..a1eed2e44a
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.c
@@ -0,0 +1,249 @@
+#include "utils.h"
+#include "vblank.h"
+#include "xmlpool.h"
+
+#include "pipe/p_context.h"
+#include "state_tracker/st_public.h"
+#include "state_tracker/st_cb_fbo.h"
+
+#include "nouveau_context.h"
+#include "nouveau_device.h"
+#include "nouveau_drm.h"
+#include "nouveau_dri.h"
+#include "nouveau_local.h"
+#include "nouveau_screen.h"
+#include "nouveau_swapbuffers.h"
+
+#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 10
+#error nouveau_drm.h version does not match expected version
+#endif
+
+PUBLIC const char __driConfigOptions[] =
+DRI_CONF_BEGIN
+DRI_CONF_END;
+static const GLuint __driNConfigOptions = 0;
+
+extern const struct dri_extension common_extensions[];
+extern const struct dri_extension nv40_extensions[];
+
+static GLboolean
+nouveau_screen_create(__DRIscreenPrivate *driScrnPriv)
+{
+ struct nouveau_dri *nv_dri = driScrnPriv->pDevPriv;
+ struct nouveau_screen *nv_screen;
+ int ret;
+
+ if (driScrnPriv->devPrivSize != sizeof(struct nouveau_dri)) {
+ NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
+ return GL_FALSE;
+ }
+
+ nv_screen = CALLOC_STRUCT(nouveau_screen);
+ if (!nv_screen)
+ return GL_FALSE;
+ nv_screen->driScrnPriv = driScrnPriv;
+ driScrnPriv->private = (void *)nv_screen;
+
+ driParseOptionInfo(&nv_screen->option_cache,
+ __driConfigOptions, __driNConfigOptions);
+
+ if ((ret = nouveau_device_open_existing(&nv_screen->device, 0,
+ driScrnPriv->fd, 0))) {
+ NOUVEAU_ERR("Failed opening nouveau device: %d\n", ret);
+ return GL_FALSE;
+ }
+
+ nv_screen->front_offset = nv_dri->front_offset;
+ nv_screen->front_pitch = nv_dri->front_pitch * (nv_dri->bpp / 8);
+ nv_screen->front_cpp = nv_dri->bpp / 8;
+ nv_screen->front_height = nv_dri->height;
+
+ return GL_TRUE;
+}
+
+static void
+nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
+{
+ struct nouveau_screen *nv_screen = driScrnPriv->private;
+
+ driScrnPriv->private = NULL;
+ FREE(nv_screen);
+}
+
+static GLboolean
+nouveau_create_buffer(__DRIscreenPrivate * driScrnPriv,
+ __DRIdrawablePrivate * driDrawPriv,
+ const __GLcontextModes *glVis, GLboolean pixmapBuffer)
+{
+ struct nouveau_framebuffer *nvfb;
+
+ if (pixmapBuffer)
+ return GL_FALSE;
+
+ nvfb = CALLOC_STRUCT(nouveau_framebuffer);
+ if (!nvfb)
+ return GL_FALSE;
+
+ nvfb->stfb = st_create_framebuffer(glVis, GL_TRUE, (void*)nvfb);
+ if (!nvfb->stfb) {
+ free(nvfb);
+ return GL_FALSE;
+ }
+
+ driDrawPriv->driverPrivate = (void *)nvfb;
+ return GL_TRUE;
+}
+
+static void
+nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
+{
+ struct nouveau_framebuffer *nvfb;
+
+ nvfb = (struct nouveau_framebuffer *)driDrawPriv;
+ st_unreference_framebuffer(&nvfb->stfb);
+ free(nvfb);
+}
+
+static struct __DriverAPIRec
+nouveau_api = {
+ .InitDriver = nouveau_screen_create,
+ .DestroyScreen = nouveau_screen_destroy,
+ .CreateContext = nouveau_context_create,
+ .DestroyContext = nouveau_context_destroy,
+ .CreateBuffer = nouveau_create_buffer,
+ .DestroyBuffer = nouveau_destroy_buffer,
+ .SwapBuffers = nouveau_swap_buffers,
+ .MakeCurrent = nouveau_context_bind,
+ .UnbindContext = nouveau_context_unbind,
+ .GetSwapInfo = NULL,
+ .GetMSC = NULL,
+ .WaitForMSC = NULL,
+ .WaitForSBC = NULL,
+ .SwapBuffersMSC = NULL,
+ .CopySubBuffer = nouveau_copy_sub_buffer,
+ .setTexOffset = NULL
+};
+
+static __GLcontextModes *
+nouveau_fill_in_modes(unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer)
+{
+ __GLcontextModes * modes;
+ __GLcontextModes * m;
+ unsigned num_modes;
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ int i;
+
+ static const struct {
+ GLenum format;
+ GLenum type;
+ } fb_format_array[] = {
+ { GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
+ { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
+ { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
+ };
+
+ /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
+ * support pageflipping at all.
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
+ };
+
+ u_int8_t depth_bits_array[4] = { 0, 16, 24, 24 };
+ u_int8_t stencil_bits_array[4] = { 0, 0, 0, 8 };
+
+ depth_buffer_factor = 4;
+ back_buffer_factor = (have_back_buffer) ? 3 : 1;
+
+ num_modes = ((pixel_bits==16) ? 1 : 2) *
+ depth_buffer_factor * back_buffer_factor * 4;
+ modes = (*dri_interface->createContextModes)(num_modes,
+ sizeof(__GLcontextModes));
+ m = modes;
+
+ for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
+ if (!driFillInModes(&m, fb_format_array[i].format,
+ fb_format_array[i].type,
+ depth_bits_array,
+ stencil_bits_array,
+ depth_buffer_factor,
+ back_buffer_modes,
+ back_buffer_factor,
+ GLX_TRUE_COLOR)) {
+ fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__ );
+ return NULL;
+ }
+
+ if (!driFillInModes(&m, fb_format_array[i].format,
+ fb_format_array[i].type,
+ depth_bits_array,
+ stencil_bits_array,
+ depth_buffer_factor,
+ back_buffer_modes,
+ back_buffer_factor,
+ GLX_DIRECT_COLOR)) {
+ fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__ );
+ return NULL;
+ }
+ }
+
+ return modes;
+}
+PUBLIC void *
+__driCreateNewScreen_20050727(__DRInativeDisplay *dpy, int scrn,
+ __DRIscreen *psc, const __GLcontextModes * modes,
+ const __DRIversion * ddx_version,
+ const __DRIversion * dri_version,
+ const __DRIversion * drm_version,
+ const __DRIframebuffer * frame_buffer,
+ void * pSAREA, int fd, int internal_api_version,
+ const __DRIinterfaceMethods * interface,
+ __GLcontextModes ** driver_modes)
+{
+ __DRIscreenPrivate *psp;
+ static const __DRIversion ddx_expected = { 1, 2, 0 };
+ static const __DRIversion dri_expected = { 4, 0, 0 };
+ static const __DRIversion drm_expected =
+ { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
+ struct nouveau_dri *nv_dri = NULL;
+
+ dri_interface = interface;
+
+ if (!driCheckDriDdxDrmVersions2("nouveau",
+ dri_version, &dri_expected,
+ ddx_version, &ddx_expected,
+ drm_version, &drm_expected)) {
+ return NULL;
+ }
+
+ if (drm_expected.patch != drm_version->patch) {
+ fprintf(stderr, "Incompatible DRM patch level.\n"
+ "Expected: %d\n" "Current : %d\n",
+ drm_expected.patch, drm_version->patch);
+ return NULL;
+ }
+
+ psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
+ ddx_version, dri_version, drm_version,
+ frame_buffer, pSAREA, fd,
+ internal_api_version,
+ &nouveau_api);
+ if (psp == NULL)
+ return NULL;
+ nv_dri = psp->pDevPriv;
+
+ *driver_modes = nouveau_fill_in_modes(nv_dri->bpp,
+ (nv_dri->bpp == 16) ? 16 : 24,
+ (nv_dri->bpp == 16) ? 0 : 8,
+ 1);
+
+ driInitExtensions(NULL, common_extensions, GL_FALSE);
+ driInitExtensions(NULL, nv40_extensions, GL_FALSE);
+
+ return (void *)psp;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h
new file mode 100644
index 0000000000..019823bd44
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_screen.h
@@ -0,0 +1,19 @@
+#ifndef __NOUVEAU_SCREEN_H__
+#define __NOUVEAU_SCREEN_H__
+
+#include "xmlconfig.h"
+#include "nouveau_device.h"
+
+struct nouveau_screen {
+ __DRIscreenPrivate *driScrnPriv;
+ driOptionCache option_cache;
+
+ struct nouveau_device *device;
+
+ uint32_t front_offset;
+ uint32_t front_pitch;
+ uint32_t front_cpp;
+ uint32_t front_height;
+};
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c
new file mode 100644
index 0000000000..91bf243f42
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.c
@@ -0,0 +1,86 @@
+#include "main/glheader.h"
+#include "glapi/glthread.h"
+#include <GL/internal/glcore.h>
+
+#include "pipe/p_context.h"
+#include "state_tracker/st_public.h"
+#include "state_tracker/st_context.h"
+#include "state_tracker/st_cb_fbo.h"
+
+#include "nouveau_context.h"
+#include "nouveau_local.h"
+#include "nouveau_screen.h"
+#include "nouveau_swapbuffers.h"
+
+void
+nouveau_copy_buffer(__DRIdrawablePrivate *dPriv, struct pipe_surface *surf,
+ const drm_clip_rect_t *rect)
+{
+ struct nouveau_context *nv = dPriv->driContextPriv->driverPrivate;
+ drm_clip_rect_t *pbox;
+ int nbox, i;
+
+ LOCK_HARDWARE(nv);
+ if (!dPriv->numClipRects) {
+ UNLOCK_HARDWARE(nv);
+ return;
+ }
+ pbox = dPriv->pClipRects;
+ nbox = dPriv->numClipRects;
+
+ nv->surface_copy_prep(nv, nv->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->surface_copy(nv, dx, dy, sx, sy, w, h);
+ }
+
+ FIRE_RING();
+ UNLOCK_HARDWARE(nv);
+
+ if (nv->last_stamp != dPriv->lastStamp) {
+ struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
+ st_resize_framebuffer(nvfb->stfb, dPriv->w, dPriv->h);
+ nv->last_stamp = dPriv->lastStamp;
+ }
+}
+
+void
+nouveau_copy_sub_buffer(__DRIdrawablePrivate *dPriv, int x, int y, int w, int h)
+{
+ struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
+ struct pipe_surface *surf;
+
+ surf = st_get_framebuffer_surface(nvfb->stfb, ST_SURFACE_BACK_LEFT);
+ if (surf) {
+ drm_clip_rect_t rect;
+ rect.x1 = x;
+ rect.y1 = y;
+ rect.x2 = x + w;
+ rect.y2 = y + h;
+
+ st_notify_swapbuffers(nvfb->stfb);
+ nouveau_copy_buffer(dPriv, surf, &rect);
+ }
+}
+
+void
+nouveau_swap_buffers(__DRIdrawablePrivate *dPriv)
+{
+ struct nouveau_framebuffer *nvfb = dPriv->driverPrivate;
+ struct pipe_surface *surf;
+
+ surf = st_get_framebuffer_surface(nvfb->stfb, ST_SURFACE_BACK_LEFT);
+ if (surf) {
+ st_notify_swapbuffers(nvfb->stfb);
+ nouveau_copy_buffer(dPriv, surf, NULL);
+ }
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h
new file mode 100644
index 0000000000..825d3da6da
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_swapbuffers.h
@@ -0,0 +1,10 @@
+#ifndef __NOUVEAU_SWAPBUFFERS_H__
+#define __NOUVEAU_SWAPBUFFERS_H__
+
+extern void nouveau_copy_buffer(__DRIdrawablePrivate *, struct pipe_surface *,
+ const drm_clip_rect_t *);
+extern void nouveau_copy_sub_buffer(__DRIdrawablePrivate *,
+ int x, int y, int w, int h);
+extern void nouveau_swap_buffers(__DRIdrawablePrivate *);
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
new file mode 100644
index 0000000000..e6481a20f2
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
@@ -0,0 +1,143 @@
+#include "pipe/p_util.h"
+
+#include "nouveau_context.h"
+#include "nouveau_winsys_pipe.h"
+
+#include "pipe/nouveau/nouveau_winsys.h"
+
+static int
+nouveau_pipe_notifier_alloc(struct nouveau_winsys *nvws, int count,
+ struct nouveau_notifier **notify)
+{
+ struct nouveau_context *nv = nvws->nv;
+
+ return nouveau_notifier_alloc(nv->channel, nv->next_handle++,
+ count, notify);
+}
+
+static int
+nouveau_pipe_grobj_alloc(struct nouveau_winsys *nvws, int grclass,
+ struct nouveau_grobj **grobj)
+{
+ struct nouveau_context *nv = nvws->nv;
+
+ return nouveau_grobj_alloc(nv->channel, nv->next_handle++,
+ grclass, grobj);
+}
+
+uint32_t *
+nouveau_pipe_dma_beginp(struct nouveau_grobj *grobj, int mthd, int size)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(grobj->channel);
+ uint32_t *pushbuf;
+
+ if (!nvchan->pb_tail || nvchan->pb_tail->remaining < (size + 1))
+ nouveau_pushbuf_flush(grobj->channel);
+
+ if (grobj->bound == NOUVEAU_GROBJ_UNBOUND)
+ nouveau_dma_subc_bind(grobj);
+ nvchan->subchannel[grobj->subc].seq = nvchan->subc_sequence++;
+
+ pushbuf = nvchan->pb_tail->cur;
+ nvchan->pb_tail->cur += (size + 1);
+ nvchan->pb_tail->remaining -= (size + 1);
+
+ (*pushbuf++) = ((grobj->subc << 13) | (size << 18) | mthd);
+ return pushbuf;
+}
+
+void
+nouveau_pipe_dma_kickoff(struct nouveau_channel *chan)
+{
+ nouveau_pushbuf_flush(chan);
+}
+
+static int
+nouveau_pipe_surface_copy(struct nouveau_winsys *nvws, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, struct pipe_surface *src,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ struct nouveau_context *nv = nvws->nv;
+
+ if (nv->surface_copy_prep(nv, dst, src))
+ return 1;
+ nv->surface_copy(nv, dx, dy, sx, sy, w, h);
+ nv->surface_copy_done(nv);
+
+ return 0;
+}
+
+static int
+nouveau_pipe_surface_fill(struct nouveau_winsys *nvws, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, unsigned w, unsigned h,
+ unsigned value)
+{
+ if (nvws->nv->surface_fill(nvws->nv, dst, dx, dy, w, h, value))
+ return 1;
+ return 0;
+}
+
+static int
+nouveau_pipe_surface_data(struct nouveau_winsys *nvws, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, const void *src,
+ unsigned src_pitch, unsigned sx, unsigned sy,
+ unsigned w, unsigned h)
+{
+ if (nvws->nv->surface_data(nvws->nv, dst, dx, dy, src, src_pitch, sx,
+ sy, w, h))
+ return 1;
+ return 0;
+}
+
+struct pipe_context *
+nouveau_pipe_create(struct nouveau_context *nv)
+{
+ struct nouveau_winsys *nvws = CALLOC_STRUCT(nouveau_winsys);
+ struct pipe_context *(*hw_create)(struct pipe_winsys *,
+ struct nouveau_winsys *,
+ unsigned);
+
+ if (!nvws)
+ return NULL;
+
+ switch (nv->chipset & 0xf0) {
+ case 0x40:
+ hw_create = nv40_create;
+ break;
+ case 0x50:
+ case 0x80:
+ hw_create = nv50_create;
+ break;
+ default:
+ NOUVEAU_ERR("Unknown chipset NV%02x\n", (int)nv->chipset);
+ return NULL;
+ }
+
+ nvws->nv = nv;
+ nvws->channel = nv->channel;
+
+ nvws->res_init = nouveau_resource_init;
+ nvws->res_alloc = nouveau_resource_alloc;
+ nvws->res_free = nouveau_resource_free;
+
+ nvws->begin_ring = nouveau_pipe_dma_beginp;
+ nvws->out_reloc = nouveau_pushbuf_emit_reloc;
+ nvws->fire_ring = nouveau_pipe_dma_kickoff;
+
+ nvws->grobj_alloc = nouveau_pipe_grobj_alloc;
+ nvws->grobj_free = nouveau_grobj_free;
+
+ nvws->notifier_alloc = nouveau_pipe_notifier_alloc;
+ nvws->notifier_free = nouveau_notifier_free;
+ nvws->notifier_reset = nouveau_notifier_reset;
+ nvws->notifier_status = nouveau_notifier_status;
+ nvws->notifier_retval = nouveau_notifier_return_val;
+ nvws->notifier_wait = nouveau_notifier_wait_status;
+
+ nvws->surface_copy = nouveau_pipe_surface_copy;
+ nvws->surface_fill = nouveau_pipe_surface_fill;
+ nvws->surface_data = nouveau_pipe_surface_data;
+
+ return hw_create(nouveau_create_pipe_winsys(nv), nvws, nv->chipset);
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c
new file mode 100644
index 0000000000..fdfad4a539
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.c
@@ -0,0 +1,229 @@
+#include "pipe/p_winsys.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_util.h"
+
+#include "nouveau_context.h"
+#include "nouveau_device.h"
+#include "nouveau_local.h"
+#include "nouveau_screen.h"
+#include "nouveau_swapbuffers.h"
+#include "nouveau_winsys_pipe.h"
+
+static void
+nouveau_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surf,
+ void *context_private)
+{
+ struct nouveau_context *nv = context_private;
+ __DRIdrawablePrivate *dPriv = nv->dri_drawable;
+
+ nouveau_copy_buffer(dPriv, surf, NULL);
+}
+
+static void
+nouveau_printf(struct pipe_winsys *pws, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+static const char *
+nouveau_get_name(struct pipe_winsys *pws)
+{
+ return "Nouveau/DRI";
+}
+
+static unsigned
+nouveau_surface_pitch(struct pipe_winsys *ws, unsigned cpp, unsigned width,
+ unsigned flags)
+{
+ unsigned pitch = width * cpp;
+
+ pitch = (pitch + 63) & ~63;
+ return pitch / cpp;
+}
+
+static struct pipe_surface *
+nouveau_surface_alloc(struct pipe_winsys *ws, unsigned format)
+{
+ struct pipe_surface *surf;
+
+ surf = CALLOC_STRUCT(pipe_surface);
+ if (!surf)
+ return NULL;
+
+ surf->format = format;
+ surf->refcount = 1;
+ surf->winsys = ws;
+ return surf;
+}
+
+static void
+nouveau_surface_release(struct pipe_winsys *ws, struct pipe_surface **s)
+{
+ struct pipe_surface *surf = *s;
+
+ *s = NULL;
+ if (--surf->refcount <= 0) {
+ if (surf->buffer)
+ ws->buffer_reference(ws, &surf->buffer, NULL);
+ free(surf);
+ }
+}
+
+static struct pipe_buffer_handle *
+nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment,
+ unsigned flags, unsigned hint)
+{
+ struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
+ struct nouveau_device *dev = nvpws->nv->nv_screen->device;
+ struct nouveau_bo *nvbo = NULL;
+
+ if (nouveau_bo_new(dev, NOUVEAU_BO_LOCAL, alignment, 0, &nvbo))
+ return NULL;
+ return (struct pipe_buffer_handle *)nvbo;
+}
+
+static struct pipe_buffer_handle *
+nouveau_pipe_bo_user_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
+{
+ struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
+ struct nouveau_device *dev = nvpws->nv->nv_screen->device;
+ struct nouveau_bo *nvbo = NULL;
+
+ if (nouveau_bo_user(dev, ptr, bytes, &nvbo))
+ return NULL;
+ return (struct pipe_buffer_handle *)nvbo;
+}
+
+static void *
+nouveau_pipe_bo_map(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
+ unsigned flags)
+{
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
+ uint32_t map_flags = 0;
+
+ if (flags & PIPE_BUFFER_FLAG_READ)
+ map_flags |= NOUVEAU_BO_RD;
+ if (flags & PIPE_BUFFER_FLAG_WRITE)
+ map_flags |= NOUVEAU_BO_WR;
+
+ if (nouveau_bo_map(nvbo, map_flags))
+ return NULL;
+ return nvbo->map;
+}
+
+static void
+nouveau_pipe_bo_unmap(struct pipe_winsys *pws, struct pipe_buffer_handle *bo)
+{
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
+
+ nouveau_bo_unmap(nvbo);
+}
+
+static void
+nouveau_pipe_bo_reference(struct pipe_winsys *pws,
+ struct pipe_buffer_handle **ptr,
+ struct pipe_buffer_handle *bo)
+{
+ struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
+ struct nouveau_context *nv = nvpws->nv;
+ struct nouveau_device *dev = nv->nv_screen->device;
+
+ if (*ptr) {
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)*ptr;
+ FIRE_RING();
+ nouveau_bo_del(&nvbo);
+ *ptr = NULL;
+ }
+
+ if (bo) {
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo, *new = NULL;
+ nouveau_bo_ref(dev, nvbo->handle, &new);
+ *ptr = bo;
+ }
+}
+
+static int
+nouveau_pipe_bo_data(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
+ unsigned size, const void *data, unsigned usage)
+{
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
+
+ if (nvbo->size != size)
+ nouveau_bo_resize(nvbo, size);
+
+ if (data) {
+ if (nouveau_bo_map(nvbo, NOUVEAU_BO_WR))
+ return 1;
+ memcpy(nvbo->map, data, size);
+ nouveau_bo_unmap(nvbo);
+ }
+
+ return 0;
+}
+
+static int
+nouveau_pipe_bo_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *bo,
+ unsigned long offset, unsigned long size,
+ const void *data)
+{
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
+
+ if (nouveau_bo_map(nvbo, NOUVEAU_BO_WR))
+ return 1;
+ memcpy(nvbo->map + offset, data, size);
+ nouveau_bo_unmap(nvbo);
+
+ return 0;
+}
+
+static int
+nouveau_pipe_bo_get_subdata(struct pipe_winsys *pws,
+ struct pipe_buffer_handle *bo, unsigned long offset,
+ unsigned long size, void *data)
+{
+ struct nouveau_bo *nvbo = (struct nouveau_bo *)bo;
+
+ if (nouveau_bo_map(nvbo, NOUVEAU_BO_RD))
+ return 1;
+ memcpy(data, nvbo->map + offset, size);
+ nouveau_bo_unmap(nvbo);
+
+ return 0;
+}
+
+struct pipe_winsys *
+nouveau_create_pipe_winsys(struct nouveau_context *nv)
+{
+ struct nouveau_pipe_winsys *nvpws;
+ struct pipe_winsys *pws;
+
+ nvpws = CALLOC_STRUCT(nouveau_pipe_winsys);
+ if (!nvpws)
+ return NULL;
+ nvpws->nv = nv;
+ pws = &nvpws->pws;
+
+ pws->flush_frontbuffer = nouveau_flush_frontbuffer;
+ pws->printf = nouveau_printf;
+
+ pws->surface_pitch = nouveau_surface_pitch;
+ pws->surface_alloc = nouveau_surface_alloc;
+ pws->surface_release = nouveau_surface_release;
+
+ pws->buffer_create = nouveau_pipe_bo_create;
+ pws->user_buffer_create = nouveau_pipe_bo_user_create;
+ pws->buffer_map = nouveau_pipe_bo_map;
+ pws->buffer_unmap = nouveau_pipe_bo_unmap;
+ pws->buffer_reference = nouveau_pipe_bo_reference;
+ pws->buffer_data = nouveau_pipe_bo_data;
+ pws->buffer_subdata = nouveau_pipe_bo_subdata;
+ pws->buffer_get_subdata= nouveau_pipe_bo_get_subdata;
+
+ pws->get_name = nouveau_get_name;
+
+ return &nvpws->pws;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h
new file mode 100644
index 0000000000..bcac60851c
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_pipe.h
@@ -0,0 +1,23 @@
+#ifndef NOUVEAU_PIPE_WINSYS_H
+#define NOUVEAU_PIPE_WINSYS_H
+
+#include "pipe/p_context.h"
+#include "pipe/p_winsys.h"
+#include "nouveau_context.h"
+
+struct nouveau_pipe_winsys {
+ struct pipe_winsys pws;
+
+ struct nouveau_context *nv;
+};
+
+extern struct pipe_winsys *
+nouveau_create_pipe_winsys(struct nouveau_context *nv);
+
+struct pipe_context *
+nouveau_create_softpipe(struct nouveau_context *nv);
+
+struct pipe_context *
+nouveau_pipe_create(struct nouveau_context *nv);
+
+#endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c
new file mode 100644
index 0000000000..ebce4ddede
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys_softpipe.c
@@ -0,0 +1,82 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+/*
+ * Authors: Keith Whitwell <keithw-at-tungstengraphics-dot-com>
+ */
+
+#include "imports.h"
+
+#include "pipe/softpipe/sp_winsys.h"
+#include "pipe/p_defines.h"
+
+#include "nouveau_context.h"
+#include "nouveau_winsys_pipe.h"
+
+struct nouveau_softpipe_winsys {
+ struct softpipe_winsys sws;
+ struct nouveau_context *nv;
+};
+
+/**
+ * Return list of surface formats supported by this driver.
+ */
+static boolean
+nouveau_is_format_supported(struct softpipe_winsys *sws, uint format)
+{
+ switch (format) {
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ case PIPE_FORMAT_R5G6B5_UNORM:
+ case PIPE_FORMAT_S8Z24_UNORM:
+ return TRUE;
+ default:
+ break;
+ };
+
+ return FALSE;
+}
+
+
+
+struct pipe_context *
+nouveau_create_softpipe(struct nouveau_context *nv)
+{
+ struct nouveau_softpipe_winsys *nvsws;
+
+ nvsws = CALLOC_STRUCT(nouveau_softpipe_winsys);
+
+ /* Fill in this struct with callbacks that softpipe will need to
+ * communicate with the window system, buffer manager, etc.
+ */
+ nvsws->sws.is_format_supported = nouveau_is_format_supported;
+ nvsws->nv = nv;
+
+ /* Create the softpipe context:
+ */
+ return softpipe_create(nouveau_create_pipe_winsys(nv), &nvsws->sws);
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nv04_surface.c b/src/mesa/drivers/dri/nouveau_winsys/nv04_surface.c
new file mode 100644
index 0000000000..67e2514026
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nv04_surface.c
@@ -0,0 +1,231 @@
+#include "pipe/p_context.h"
+
+#include "nouveau_context.h"
+
+static INLINE int
+nv04_surface_format(int cpp)
+{
+ switch (cpp) {
+ case 1: return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
+ case 2: return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
+ case 4: return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
+ default:
+ return -1;
+ }
+}
+
+static INLINE int
+nv04_rect_format(int cpp)
+{
+ switch (cpp) {
+ case 1: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
+ case 2: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
+ case 4: return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
+ default:
+ return -1;
+ }
+}
+
+static void
+nv04_surface_copy_m2mf(struct nouveau_context *nv, unsigned dx, unsigned dy,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ struct pipe_surface *dst = nv->surf_dst;
+ struct pipe_surface *src = nv->surf_dst;
+ unsigned dst_offset, src_offset;
+
+ dst_offset = dst->offset + (dy * dst->pitch + dx) * dst->cpp;
+ src_offset = src->offset + (sy * src->pitch + sx) * src->cpp;
+
+ while (h) {
+ int count = (h > 2047) ? 2047 : h;
+
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ OUT_RELOCl(src->buffer, src_offset, NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_GART | NOUVEAU_BO_RD);
+ OUT_RELOCl(dst->buffer, dst_offset, NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_GART | NOUVEAU_BO_WR);
+ OUT_RING (src->pitch * src->cpp);
+ OUT_RING (dst->pitch * dst->cpp);
+ OUT_RING (w * src->cpp);
+ OUT_RING (count);
+ OUT_RING (0x0101);
+ OUT_RING (0);
+
+ h -= count;
+ src_offset += src->pitch * count;
+ dst_offset += dst->pitch * count;
+ }
+}
+
+static void
+nv04_surface_copy_blit(struct nouveau_context *nv, unsigned dx, unsigned dy,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ BEGIN_RING(NvImageBlit, 0x0300, 3);
+ OUT_RING ((sy << 16) | sx);
+ OUT_RING ((dy << 16) | dx);
+ OUT_RING (( h << 16) | w);
+}
+
+static int
+nv04_surface_copy_prep(struct nouveau_context *nv, struct pipe_surface *dst,
+ struct pipe_surface *src)
+{
+ int format;
+
+ if (src->cpp != dst->cpp)
+ return 1;
+
+ /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
+ * to NV_MEMORY_TO_MEMORY_FORMAT in this case.
+ */
+ if ((src->offset & 63) || (dst->offset & 63)) {
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+ OUT_RELOCo(src->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_RD);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM |
+ NOUVEAU_BO_WR);
+
+ nv->surface_copy = nv04_surface_copy_m2mf;
+ nv->surf_dst = dst;
+ nv->surf_src = src;
+ return 0;
+
+ }
+
+ if ((format = nv04_surface_format(dst->cpp)) < 0) {
+ NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
+ return 1;
+ }
+ nv->surface_copy = nv04_surface_copy_blit;
+
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RELOCo(src->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
+ OUT_RING (format);
+ OUT_RING (((dst->pitch * dst->cpp) << 16) | (src->pitch * src->cpp));
+ OUT_RELOCl(src->buffer, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+ OUT_RELOCl(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+ return 0;
+}
+
+static void
+nv04_surface_copy_done(struct nouveau_context *nv)
+{
+ FIRE_RING();
+}
+
+static int
+nv04_surface_fill(struct nouveau_context *nv, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, unsigned w, unsigned h,
+ unsigned value)
+{
+ int cs2d_format, gdirect_format;
+
+ if ((cs2d_format = nv04_surface_format(dst->cpp)) < 0) {
+ NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
+ return 1;
+ }
+
+ if ((gdirect_format = nv04_rect_format(dst->cpp)) < 0) {
+ NOUVEAU_ERR("Bad cpp = %d\n", dst->cpp);
+ return 1;
+ }
+
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
+ OUT_RING (cs2d_format);
+ OUT_RING (((dst->pitch * dst->cpp) << 16) | (dst->pitch * dst->cpp));
+ OUT_RELOCl(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ OUT_RELOCl(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
+ OUT_RING (gdirect_format);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
+ OUT_RING (value);
+ BEGIN_RING(NvGdiRect,
+ NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
+ OUT_RING ((dx << 16) | dy);
+ OUT_RING (( w << 16) | h);
+
+ FIRE_RING();
+ return 0;
+}
+
+static int
+nv04_surface_data(struct nouveau_context *nv, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, const void *src, unsigned src_pitch,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ NOUVEAU_ERR("unimplemented!!\n");
+ return 0;
+}
+
+int
+nouveau_surface_init_nv04(struct nouveau_context *nv)
+{
+ unsigned class;
+ int ret;
+
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, 0x39,
+ &nv->NvM2MF))) {
+ NOUVEAU_ERR("Error creating m2mf object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+
+ class = nv->chipset < 0x10 ? NV04_CONTEXT_SURFACES_2D :
+ NV10_CONTEXT_SURFACES_2D;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvCtxSurf2D))) {
+ NOUVEAU_ERR("Error creating 2D surface object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvCtxSurf2D, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
+ OUT_RING (nv->channel->vram->handle);
+ OUT_RING (nv->channel->vram->handle);
+
+ class = nv->chipset < 0x10 ? NV_IMAGE_BLIT :
+ NV12_IMAGE_BLIT;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvImageBlit))) {
+ NOUVEAU_ERR("Error creating blit object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_SURFACE, 1);
+ OUT_RING (nv->NvCtxSurf2D->handle);
+ BEGIN_RING(NvImageBlit, NV_IMAGE_BLIT_OPERATION, 1);
+ OUT_RING (NV_IMAGE_BLIT_OPERATION_SRCCOPY);
+
+ class = NV04_GDI_RECTANGLE_TEXT;
+ if ((ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, class,
+ &nv->NvGdiRect))) {
+ NOUVEAU_ERR("Error creating rect object: %d\n", ret);
+ return 1;
+ }
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
+ OUT_RING (nv->NvCtxSurf2D->handle);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
+ OUT_RING (NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY);
+ BEGIN_RING(NvGdiRect, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
+ OUT_RING (NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
+
+ nv->surface_copy_prep = nv04_surface_copy_prep;
+ nv->surface_copy = nv04_surface_copy_blit;
+ nv->surface_copy_done = nv04_surface_copy_done;
+ nv->surface_fill = nv04_surface_fill;
+ nv->surface_data = nv04_surface_data;
+ return 0;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nv50_surface.c b/src/mesa/drivers/dri/nouveau_winsys/nv50_surface.c
new file mode 100644
index 0000000000..2a95b1fcd3
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nv50_surface.c
@@ -0,0 +1,170 @@
+#include "pipe/p_context.h"
+
+#include "nouveau_context.h"
+
+static INLINE int
+nv50_format(int cpp)
+{
+ switch (cpp) {
+ case 4: return NV50_2D_DST_FORMAT_32BPP;
+ case 3: return NV50_2D_DST_FORMAT_24BPP;
+ case 2: return NV50_2D_DST_FORMAT_16BPP;
+ case 1: return NV50_2D_DST_FORMAT_8BPP;
+ default:
+ return -1;
+ }
+}
+
+static int
+nv50_surface_copy_prep(struct nouveau_context *nv,
+ struct pipe_surface *dst, struct pipe_surface *src)
+{
+ int surf_format;
+
+ assert(src->cpp == dst->cpp);
+
+ surf_format = nv50_format(dst->cpp);
+ assert(surf_format >= 0);
+
+ BEGIN_RING(Nv2D, NV50_2D_DMA_IN_MEMORY0, 2);
+ OUT_RELOCo(src->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+
+ BEGIN_RING(Nv2D, NV50_2D_DST_FORMAT, 2);
+ OUT_RING (surf_format);
+ OUT_RING (1);
+ BEGIN_RING(Nv2D, NV50_2D_DST_PITCH, 5);
+ OUT_RING (dst->pitch * dst->cpp);
+ OUT_RING (dst->pitch);
+ OUT_RING (dst->height);
+ OUT_RELOCh(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ OUT_RELOCl(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(Nv2D, NV50_2D_CLIP_X, 4);
+ OUT_RING (0);
+ OUT_RING (0);
+ OUT_RING (dst->pitch);
+ OUT_RING (dst->height);
+
+ BEGIN_RING(Nv2D, NV50_2D_SRC_FORMAT, 2);
+ OUT_RING (surf_format);
+ OUT_RING (1);
+ BEGIN_RING(Nv2D, NV50_2D_SRC_PITCH, 5);
+ OUT_RING (src->pitch * src->cpp);
+ OUT_RING (src->pitch);
+ OUT_RING (src->height);
+ OUT_RELOCh(src->buffer, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+ OUT_RELOCl(src->buffer, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
+
+ return 0;
+}
+
+static void
+nv50_surface_copy(struct nouveau_context *nv, unsigned dx, unsigned dy,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ BEGIN_RING(Nv2D, 0x0110, 1);
+ OUT_RING (0);
+ BEGIN_RING(Nv2D, NV50_2D_BLIT_DST_X, 12);
+ OUT_RING (dx);
+ OUT_RING (dy);
+ OUT_RING (w);
+ OUT_RING (h);
+ OUT_RING (0);
+ OUT_RING (1);
+ OUT_RING (0);
+ OUT_RING (1);
+ OUT_RING (0);
+ OUT_RING (sx);
+ OUT_RING (0);
+ OUT_RING (sy);
+}
+
+static void
+nv50_surface_copy_done(struct nouveau_context *nv)
+{
+ FIRE_RING();
+}
+
+static int
+nv50_surface_fill(struct nouveau_context *nv, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, unsigned w, unsigned h,
+ unsigned value)
+{
+ int surf_format, rect_format;
+
+ surf_format = nv50_format(dst->cpp);
+ if (surf_format < 0)
+ return 1;
+
+ rect_format = nv50_format(dst->cpp);
+ if (rect_format < 0)
+ return 1;
+
+ BEGIN_RING(Nv2D, NV50_2D_DMA_IN_MEMORY1, 1);
+ OUT_RELOCo(dst->buffer, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(Nv2D, NV50_2D_DST_FORMAT, 2);
+ OUT_RING (surf_format);
+ OUT_RING (1);
+ BEGIN_RING(Nv2D, NV50_2D_DST_PITCH, 5);
+ OUT_RING (dst->pitch * dst->cpp);
+ OUT_RING (dst->pitch);
+ OUT_RING (dst->height);
+ OUT_RELOCh(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ OUT_RELOCl(dst->buffer, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+ BEGIN_RING(Nv2D, NV50_2D_CLIP_X, 4);
+ OUT_RING (0);
+ OUT_RING (0);
+ OUT_RING (dst->pitch);
+ OUT_RING (dst->height);
+
+ BEGIN_RING(Nv2D, 0x0580, 3);
+ OUT_RING (4);
+ OUT_RING (rect_format);
+ OUT_RING (value);
+
+ BEGIN_RING(Nv2D, NV50_2D_RECT_X1, 4);
+ OUT_RING (dx);
+ OUT_RING (dy);
+ OUT_RING (dx + w);
+ OUT_RING (dy + h);
+
+ FIRE_RING();
+
+ return 0;
+}
+
+static int
+nv50_surface_data(struct nouveau_context *nv, struct pipe_surface *dst,
+ unsigned dx, unsigned dy, const void *src, unsigned src_pitch,
+ unsigned sx, unsigned sy, unsigned w, unsigned h)
+{
+ NOUVEAU_ERR("unimplemented!!\n");
+ return 0;
+}
+
+int
+nouveau_surface_init_nv50(struct nouveau_context *nv)
+{
+ int ret;
+
+ ret = nouveau_grobj_alloc(nv->channel, nv->next_handle++, NV50_2D,
+ &nv->Nv2D);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(Nv2D, NV50_2D_DMA_NOTIFY, 1);
+ OUT_RING (nv->sync_notifier->handle);
+ BEGIN_RING(Nv2D, NV50_2D_DMA_IN_MEMORY0, 2);
+ OUT_RING (nv->channel->vram->handle);
+ OUT_RING (nv->channel->vram->handle);
+ BEGIN_RING(Nv2D, NV50_2D_OPERATION, 1);
+ OUT_RING (NV50_2D_OPERATION_SRCCOPY);
+
+ 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;
+ nv->surface_data = nv50_surface_data;
+ return 0;
+}
+