X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fnouveau%2Fnouveau_bufferobj.c;h=dc5b1528b071343b82900b96b4606bc0396aaa1a;hb=19c46d3d7bd2dc190bb83855c4ffa65a3bc830d7;hp=d36196aeef28277aeb96e00c55bb38bf18efc194;hpb=6a3fdc3a1ea6c306d9543791bf172dd1052d7382;p=mesa.git diff --git a/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c index d36196aeef2..dc5b1528b07 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_bufferobj.c @@ -1,272 +1,177 @@ -#include "bufferobj.h" -#include "enums.h" +/* + * Copyright (C) 2009 Francisco Jerez. + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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 "nouveau_driver.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) +#include "main/bufferobj.h" -/* 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) +static inline char * +get_bufferobj_map(struct gl_buffer_object *obj, unsigned flags) { - 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); -} + struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); + void *map = NULL; + + if (nbo->sys) { + map = nbo->sys; + } else if (nbo->bo) { + nouveau_bo_map(nbo->bo, flags); + map = nbo->bo->map; + nouveau_bo_unmap(nbo->bo); + } -static void -nouveauBindBuffer(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) -{ + return map; } static struct gl_buffer_object * -nouveauNewBufferObject(GLcontext *ctx, GLuint buffer, GLenum target) +nouveau_bufferobj_new(struct gl_context *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; -} + struct nouveau_bufferobj *nbo; -static void -nouveauDeleteBuffer(GLcontext *ctx, struct gl_buffer_object *obj) -{ - nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + nbo = CALLOC_STRUCT(nouveau_bufferobj); + if (!nbo) + return NULL; - DEBUG("obj=%p\n", obj); + _mesa_initialize_buffer_object(&nbo->base, buffer, target); - if (nbo->gpu_mem) { - nouveau_mem_free(ctx, nbo->gpu_mem); - } - _mesa_delete_buffer_object(ctx, obj); + return &nbo->base; } static void -nouveauBufferData(GLcontext *ctx, GLenum target, GLsizeiptrARB size, - const GLvoid *data, GLenum usage, - struct gl_buffer_object *obj) +nouveau_bufferobj_del(struct gl_context *ctx, struct gl_buffer_object *obj) { - nouveau_buffer_object *nbo = (nouveau_buffer_object *)obj; + struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(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); + nouveau_bo_ref(NULL, &nbo->bo); + FREE(nbo->sys); + FREE(nbo); +} - if (nbo->gpu_mem && nbo->gpu_mem->size != size) - nouveau_mem_free(ctx, nbo->gpu_mem); +static GLboolean +nouveau_bufferobj_data(struct gl_context *ctx, GLenum target, GLsizeiptrARB size, + const GLvoid *data, GLenum usage, + struct gl_buffer_object *obj) +{ + struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); + int ret; - /* 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); + obj->Size = size; + obj->Usage = usage; - if (!nbo->gpu_mem) { - MESSAGE("AIII bufferobj malloc failed\n"); - return; + /* Free previous storage */ + nouveau_bo_ref(NULL, &nbo->bo); + FREE(nbo->sys); + + if (target == GL_ELEMENT_ARRAY_BUFFER_ARB || + (size < 512 && usage == GL_DYNAMIC_DRAW_ARB) || + context_chipset(ctx) < 0x10) { + /* Heuristic: keep it in system ram */ + nbo->sys = MALLOC(size); + + } else { + /* Get a hardware BO */ + ret = nouveau_bo_new(context_dev(ctx), + NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, + size, &nbo->bo); + assert(!ret); } - obj->Usage = usage; - obj->Size = size; - if (!data) - return; + if (data) + memcpy(get_bufferobj_map(obj, NOUVEAU_BO_WR), data, size); - ctx->Driver.MapBuffer(ctx, target, GL_WRITE_ONLY_ARB, obj); - _mesa_memcpy(nbo->cpu_mem->map, data, size); - ctx->Driver.UnmapBuffer(ctx, target, obj); + return GL_TRUE; } -/*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) +nouveau_bufferobj_subdata(struct gl_context *ctx, 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); + memcpy(get_bufferobj_map(obj, NOUVEAU_BO_WR) + offset, data, size); } -/*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) +nouveau_bufferobj_get_subdata(struct gl_context *ctx, 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); + memcpy(data, get_bufferobj_map(obj, NOUVEAU_BO_RD) + offset, size); } static void * -nouveauMapBuffer(GLcontext *ctx, GLenum target, GLenum access, - struct gl_buffer_object *obj) +nouveau_bufferobj_map_range(struct gl_context *ctx, GLintptr offset, + GLsizeiptr length, GLbitfield 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"); + unsigned flags = 0; + char *map; - /* 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; - } + assert(!obj->Pointer); - if (!nbo->cpu_mem) { - nbo->cpu_mem = nouveau_mem_alloc(ctx, - NOUVEAU_MEM_AGP | - NOUVEAU_MEM_MAPPED, - nbo->gpu_mem->size, - 0); + if (access & GL_MAP_READ_BIT) + flags |= NOUVEAU_BO_RD; + if (access & GL_MAP_WRITE_BIT) + flags |= NOUVEAU_BO_WR; + if (access & GL_MAP_UNSYNCHRONIZED_BIT) + flags |= NOUVEAU_BO_NOSYNC; - /* 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 + map = get_bufferobj_map(obj, flags); + if (!map) + return NULL; - /* 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 = map + offset; + obj->Offset = offset; + obj->Length = length; + obj->AccessFlags = access; - obj->Pointer = nbo->cpu_mem->map; return obj->Pointer; } static GLboolean -nouveauUnmapBuffer(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) +nouveau_bufferobj_unmap(struct gl_context *ctx, 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 + assert(obj->Pointer); obj->Pointer = NULL; + obj->Offset = 0; + obj->Length = 0; + obj->AccessFlags = 0; + return GL_TRUE; } - + void -nouveauInitBufferObjects(GLcontext *ctx) +nouveau_bufferobj_functions_init(struct dd_function_table *functions) { - 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; + functions->NewBufferObject = nouveau_bufferobj_new; + functions->DeleteBuffer = nouveau_bufferobj_del; + functions->BufferData = nouveau_bufferobj_data; + functions->BufferSubData = nouveau_bufferobj_subdata; + functions->GetBufferSubData = nouveau_bufferobj_get_subdata; + functions->MapBufferRange = nouveau_bufferobj_map_range; + functions->UnmapBuffer = nouveau_bufferobj_unmap; } -