From 9a20ae70ecda2e78ea6b52c3fd829d283434c1ad Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 27 Dec 2006 23:30:34 +1100 Subject: [PATCH] nouveau: Initial buffer object support --- src/mesa/drivers/dri/nouveau/Makefile | 1 + .../drivers/dri/nouveau/nouveau_bufferobj.c | 272 ++++++++++++++++++ .../drivers/dri/nouveau/nouveau_bufferobj.h | 27 ++ .../drivers/dri/nouveau/nouveau_context.c | 2 + .../drivers/dri/nouveau/nouveau_context.h | 1 + 5 files changed, 303 insertions(+) create mode 100644 src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c create mode 100644 src/mesa/drivers/dri/nouveau/nouveau_bufferobj.h diff --git a/src/mesa/drivers/dri/nouveau/Makefile b/src/mesa/drivers/dri/nouveau/Makefile index 962978dc7fa..d31b42a568b 100644 --- a/src/mesa/drivers/dri/nouveau/Makefile +++ b/src/mesa/drivers/dri/nouveau/Makefile @@ -8,6 +8,7 @@ LIBNAME = nouveau_dri.so MINIGLX_SOURCES = DRIVER_SOURCES = \ + nouveau_bufferobj.c \ nouveau_buffers.c \ nouveau_card.c \ nouveau_context.c \ diff --git a/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c new file mode 100644 index 00000000000..d36196aeef2 --- /dev/null +++ b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c @@ -0,0 +1,272 @@ +#include "bufferobj.h" +#include "enums.h" + +#include "nouveau_bufferobj.h" +#include "nouveau_buffers.h" +#include "nouveau_context.h" +#include "nouveau_drm.h" +#include "nouveau_object.h" +#include "nouveau_msg.h" + +#define DEBUG(fmt,args...) do { \ + if (NOUVEAU_DEBUG & DEBUG_BUFFEROBJ) { \ + fprintf(stderr, "%s: "fmt, __func__, ##args); \ + } \ +} while(0) + +/* Wrapper for nouveau_mem_gpu_offset_get() that marks the bufferobj dirty + * if the GPU modifies the data. + */ +uint32_t +nouveau_bufferobj_gpu_ref(GLcontext *ctx, GLenum access, + struct gl_buffer_object *obj) +{ + nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + + DEBUG("obj=%p, access=%s\n", obj, _mesa_lookup_enum_by_nr(access)); + + if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) + nbo->gpu_dirty = GL_TRUE; + + return nouveau_mem_gpu_offset_get(ctx, nbo->gpu_mem); +} + +static void +nouveauBindBuffer(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) +{ +} + +static struct gl_buffer_object * +nouveauNewBufferObject(GLcontext *ctx, GLuint buffer, GLenum target) +{ + nouveau_buffer_object *nbo; + + nbo = CALLOC_STRUCT(nouveau_buffer_object_t); + DEBUG("name=0x%08x, target=%s, obj=%p\n", + buffer, _mesa_lookup_enum_by_nr(target), nbo); + _mesa_initialize_buffer_object(&nbo->mesa, buffer, target); + return &nbo->mesa; +} + +static void +nouveauDeleteBuffer(GLcontext *ctx, struct gl_buffer_object *obj) +{ + nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + + DEBUG("obj=%p\n", obj); + + if (nbo->gpu_mem) { + nouveau_mem_free(ctx, nbo->gpu_mem); + } + _mesa_delete_buffer_object(ctx, obj); +} + +static void +nouveauBufferData(GLcontext *ctx, GLenum target, GLsizeiptrARB size, + const GLvoid *data, GLenum usage, + struct gl_buffer_object *obj) +{ + nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + + DEBUG("obj=%p, target=%s, usage=%s, size=%d, data=%p\n", + obj, + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(usage), + (unsigned int)size, + data); + + if (nbo->gpu_mem && nbo->gpu_mem->size != size) + nouveau_mem_free(ctx, nbo->gpu_mem); + + /* Always have the GPU access the data from VRAM if possible. For + * some "usage" values it may be better from AGP be default? + * + * TODO: At some point we should drop the NOUVEAU_MEM_MAPPED flag. + * TODO: Use the NOUVEAU_MEM_AGP_ACCEPTABLE flag. + * TODO: What about PCI-E and shared system memory? + */ + if (!nbo->gpu_mem) + nbo->gpu_mem = nouveau_mem_alloc(ctx, + NOUVEAU_MEM_FB | + NOUVEAU_MEM_MAPPED, + size, + 0); + + if (!nbo->gpu_mem) { + MESSAGE("AIII bufferobj malloc failed\n"); + return; + } + + obj->Usage = usage; + obj->Size = size; + if (!data) + return; + + ctx->Driver.MapBuffer(ctx, target, GL_WRITE_ONLY_ARB, obj); + _mesa_memcpy(nbo->cpu_mem->map, data, size); + ctx->Driver.UnmapBuffer(ctx, target, obj); +} + +/*TODO: we don't need to DMA the entire buffer like MapBuffer does.. */ +static void +nouveauBufferSubData(GLcontext *ctx, GLenum target, GLintptrARB offset, + GLsizeiptrARB size, const GLvoid *data, + struct gl_buffer_object *obj) +{ + DEBUG("obj=%p, target=%s, offset=0x%x, size=%d, data=%p\n", + obj, + _mesa_lookup_enum_by_nr(target), + (unsigned int)offset, + (unsigned int)size, + data); + + ctx->Driver.MapBuffer(ctx, target, GL_WRITE_ONLY_ARB, obj); + _mesa_memcpy((GLubyte *)obj->Pointer + offset, data, size); + ctx->Driver.UnmapBuffer(ctx, target, obj); +} + +/*TODO: we don't need to DMA the entire buffer like MapBuffer does.. */ +static void +nouveauGetBufferSubData(GLcontext *ctx, GLenum target, GLintptrARB offset, + GLsizeiptrARB size, GLvoid *data, + struct gl_buffer_object *obj) +{ + DEBUG("obj=%p, target=%s, offset=0x%x, size=%d, data=%p\n", + obj, + _mesa_lookup_enum_by_nr(target), + (unsigned int)offset, + (unsigned int)size, + data); + + ctx->Driver.MapBuffer(ctx, target, GL_READ_ONLY_ARB, obj); + _mesa_memcpy(data, (GLubyte *)obj->Pointer + offset, size); + ctx->Driver.UnmapBuffer(ctx, target, obj); +} + +static void * +nouveauMapBuffer(GLcontext *ctx, GLenum target, GLenum access, + struct gl_buffer_object *obj) +{ + nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx); + nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + + DEBUG("obj=%p, target=%s, access=%s\n", + obj, + _mesa_lookup_enum_by_nr(target), + _mesa_lookup_enum_by_nr(access)); + + if (obj->Pointer) { + DEBUG("already mapped, return NULL\n"); + return NULL; + } + +#ifdef ALLOW_MULTI_SUBCHANNEL + /* If GPU is accessing the data from VRAM, copy to faster AGP memory + * before CPU access to the buffer. + */ + if (nbo->gpu_mem->type & NOUVEAU_MEM_FB) { + DEBUG("Data in VRAM, copying to AGP for CPU access\n"); + + /* This can happen if BufferData grows the GPU-access buffer */ + if (nbo->cpu_mem && nbo->cpu_mem->size != nbo->gpu_mem->size) { + nouveau_mem_free(ctx, nbo->cpu_mem); + nbo->cpu_mem = NULL; + } + + if (!nbo->cpu_mem) { + nbo->cpu_mem = nouveau_mem_alloc(ctx, + NOUVEAU_MEM_AGP | + NOUVEAU_MEM_MAPPED, + nbo->gpu_mem->size, + 0); + + /* Mark GPU data as modified, so it gets copied to + * the new buffer */ + nbo->gpu_dirty = GL_TRUE; + } + + if (nbo->cpu_mem && nbo->gpu_dirty) { + nouveau_memformat_flat_emit(ctx, nbo->cpu_mem, + nbo->gpu_mem, + 0, 0, + nbo->gpu_mem->size); + + nouveau_notifier_wait_nop(ctx, + nmesa->syncNotifier, + NvSubMemFormat); + nbo->gpu_dirty = GL_FALSE; + } + + /* buffer isn't guaranteed to be up-to-date on the card now */ + nbo->cpu_dirty = GL_TRUE; + } +#endif + + /* If the copy to AGP failed for some reason, just return a pointer + * directly to vram.. + */ + if (!nbo->cpu_mem) { + DEBUG("Returning direct pointer to VRAM\n"); + nbo->cpu_mem = nbo->gpu_mem; + nbo->cpu_dirty = GL_FALSE; + } + + obj->Pointer = nbo->cpu_mem->map; + return obj->Pointer; +} + +static GLboolean +nouveauUnmapBuffer(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) +{ + nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx); + nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + + DEBUG("obj=%p, target=%s\n", obj, _mesa_lookup_enum_by_nr(target)); + +#ifdef ALLOW_MULTI_SUBCHANNEL + if (nbo->cpu_dirty && nbo->cpu_mem != nbo->gpu_mem) { + DEBUG("Copying potentially modified data back to GPU\n"); + + /* blit from GPU buffer -> CPU buffer */ + nouveau_memformat_flat_emit(ctx, nbo->gpu_mem, nbo->cpu_mem, + 0, 0, nbo->cpu_mem->size); + + /* buffer is now up-to-date on the hardware (or rather, will + * be by the time any other commands in this channel reference + * the data.) + */ + nbo->cpu_dirty = GL_FALSE; + + /* we can avoid this wait in some cases.. */ + nouveau_notifier_wait_nop(ctx, + nmesa->syncNotifier, + NvSubMemFormat); + + /* If it's likely CPU access to the buffer will occur often, + * keep the cpu_mem around to avoid repeated allocs. + */ + if (obj->Usage != GL_DYNAMIC_DRAW_ARB) { + + nouveau_mem_free(ctx, nbo->cpu_mem); + nbo->cpu_mem = NULL; + } + } +#endif + + obj->Pointer = NULL; + return GL_TRUE; +} + +void +nouveauInitBufferObjects(GLcontext *ctx) +{ + ctx->Driver.BindBuffer = nouveauBindBuffer; + ctx->Driver.NewBufferObject = nouveauNewBufferObject; + ctx->Driver.DeleteBuffer = nouveauDeleteBuffer; + ctx->Driver.BufferData = nouveauBufferData; + ctx->Driver.BufferSubData = nouveauBufferSubData; + ctx->Driver.GetBufferSubData = nouveauGetBufferSubData; + ctx->Driver.MapBuffer = nouveauMapBuffer; + ctx->Driver.UnmapBuffer = nouveauUnmapBuffer; +} + diff --git a/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.h b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.h new file mode 100644 index 00000000000..fccc349b836 --- /dev/null +++ b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.h @@ -0,0 +1,27 @@ +#ifndef __NOUVEAU_BUFFEROBJ_H__ +#define __NOUVEAU_BUFFEROBJ_H__ + +#include "mtypes.h" +#include "nouveau_buffers.h" + +typedef struct nouveau_buffer_object_t { + /* Base class, must be first */ + struct gl_buffer_object mesa; + + /* Memory used for GPU access to the buffer*/ + nouveau_mem * gpu_mem; + /* Buffer has been dirtied by the GPU */ + GLboolean gpu_dirty; + + /* Memory used for CPU access to the buffer */ + nouveau_mem * cpu_mem; + /* Buffer has possibly been dirtied by the CPU */ + GLboolean cpu_dirty; +} nouveau_buffer_object; + +extern uint32_t nouveau_bufferobj_gpu_ref(GLcontext *ctx, GLenum access, + struct gl_buffer_object *obj); + +extern void nouveauInitBufferObjects(GLcontext *ctx); + +#endif diff --git a/src/mesa/drivers/dri/nouveau/nouveau_context.c b/src/mesa/drivers/dri/nouveau/nouveau_context.c index bb67f72f4a8..79da46fc0b6 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_context.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_context.c @@ -65,6 +65,7 @@ static const struct dri_debug_control debug_control[] = { { "shaders" , DEBUG_SHADERS }, { "mem" , DEBUG_MEM }, + { "bufferobj" , DEBUG_BUFFEROBJ }, { NULL , 0 } }; @@ -224,6 +225,7 @@ GLboolean nouveauCreateContext( const __GLcontextModes *glVisual, break; } + nouveauInitBufferObjects(ctx); if (!nouveauSyncInitFuncs(ctx)) return GL_FALSE; nmesa->hw_func.InitCard(nmesa); diff --git a/src/mesa/drivers/dri/nouveau/nouveau_context.h b/src/mesa/drivers/dri/nouveau/nouveau_context.h index b0952070c77..134e2a417e3 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_context.h +++ b/src/mesa/drivers/dri/nouveau/nouveau_context.h @@ -218,6 +218,7 @@ extern int NOUVEAU_DEBUG; #define DEBUG_SHADERS 0x00000001 #define DEBUG_MEM 0x00000002 +#define DEBUG_BUFFEROBJ 0x00000004 #endif /* __NOUVEAU_CONTEXT_H__ */ -- 2.30.2