1/* 2 * Copyright (C) 2009 Francisco Jerez. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27#include "nouveau_driver.h" 28#include "nouveau_bufferobj.h" 29#include "nouveau_context.h" 30 31#include "main/bufferobj.h" 32#include "util/u_memory.h" 33 34static inline char * 35get_bufferobj_map(struct gl_context *ctx, struct gl_buffer_object *obj, 36 unsigned flags) 37{ 38 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 39 void *map = NULL; 40 41 if (nbo->sys) { 42 map = nbo->sys; 43 } else if (nbo->bo) { 44 nouveau_bo_map(nbo->bo, flags, context_client(ctx)); 45 map = nbo->bo->map; 46 } 47 48 return map; 49} 50 51static struct gl_buffer_object * 52nouveau_bufferobj_new(struct gl_context *ctx, GLuint buffer) 53{ 54 struct nouveau_bufferobj *nbo; 55 56 nbo = CALLOC_STRUCT(nouveau_bufferobj); 57 if (!nbo) 58 return NULL; 59 60 _mesa_initialize_buffer_object(ctx, &nbo->base, buffer); 61 62 return &nbo->base; 63} 64 65static void 66nouveau_bufferobj_del(struct gl_context *ctx, struct gl_buffer_object *obj) 67{ 68 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 69 70 nouveau_bo_ref(NULL, &nbo->bo); 71 free(nbo->sys); 72 free(nbo); 73} 74 75static GLboolean 76nouveau_bufferobj_data(struct gl_context *ctx, GLenum target, GLsizeiptrARB size, 77 const GLvoid *data, GLenum usage, GLbitfield storageFlags, 78 struct gl_buffer_object *obj) 79{ 80 struct nouveau_bufferobj *nbo = to_nouveau_bufferobj(obj); 81 int ret; 82 83 obj->Size = size; 84 obj->Usage = usage; 85 obj->StorageFlags = storageFlags; 86 87 /* Free previous storage */ 88 nouveau_bo_ref(NULL, &nbo->bo); 89 free(nbo->sys); 90 nbo->sys = NULL; 91 92 if (target == GL_ELEMENT_ARRAY_BUFFER_ARB || 93 (size < 512 && usage == GL_DYNAMIC_DRAW_ARB) || 94 context_chipset(ctx) < 0x10) { 95 /* Heuristic: keep it in system ram */ 96 nbo->sys = malloc(size); 97 98 } else { 99 /* Get a hardware BO */ 100 ret = nouveau_bo_new(context_dev(ctx), 101 NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 102 ctx->Const.MinMapBufferAlignment, 103 size, NULL, &nbo->bo); 104 assert(!ret); 105 } 106 107 if (data) 108 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR), data, size); 109 110 return GL_TRUE; 111} 112 113static void 114nouveau_bufferobj_subdata(struct gl_context *ctx, GLintptrARB offset, 115 GLsizeiptrARB size, const GLvoid *data, 116 struct gl_buffer_object *obj) 117{ 118 memcpy(get_bufferobj_map(ctx, obj, NOUVEAU_BO_WR) + offset, data, size); 119} 120 121static void 122nouveau_bufferobj_get_subdata(struct gl_context *ctx, GLintptrARB offset, 123 GLsizeiptrARB size, GLvoid *data, 124 struct gl_buffer_object *obj) 125{ 126 memcpy(data, get_bufferobj_map(ctx, obj, NOUVEAU_BO_RD) + offset, size); 127} 128 129static void * 130nouveau_bufferobj_map_range(struct gl_context *ctx, GLintptr offset, 131 GLsizeiptr length, GLbitfield access, 132 struct gl_buffer_object *obj, 133 gl_map_buffer_index index) 134{ 135 unsigned flags = 0; 136 char *map; 137 138 assert(!obj->Mappings[index].Pointer); 139 140 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) { 141 if (access & GL_MAP_READ_BIT) 142 flags |= NOUVEAU_BO_RD; 143 if (access & GL_MAP_WRITE_BIT) 144 flags |= NOUVEAU_BO_WR; 145 } 146 147 map = get_bufferobj_map(ctx, obj, flags); 148 if (!map) 149 return NULL; 150 151 obj->Mappings[index].Pointer = map + offset; 152 obj->Mappings[index].Offset = offset; 153 obj->Mappings[index].Length = length; 154 obj->Mappings[index].AccessFlags = access; 155 156 return obj->Mappings[index].Pointer; 157} 158 159static GLboolean 160nouveau_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj, 161 gl_map_buffer_index index) 162{ 163 assert(obj->Mappings[index].Pointer); 164 165 obj->Mappings[index].Pointer = NULL; 166 obj->Mappings[index].Offset = 0; 167 obj->Mappings[index].Length = 0; 168 obj->Mappings[index].AccessFlags = 0; 169 170 return GL_TRUE; 171} 172 173void 174nouveau_bufferobj_functions_init(struct dd_function_table *functions) 175{ 176 functions->NewBufferObject = nouveau_bufferobj_new; 177 functions->DeleteBuffer = nouveau_bufferobj_del; 178 functions->BufferData = nouveau_bufferobj_data; 179 functions->BufferSubData = nouveau_bufferobj_subdata; 180 functions->GetBufferSubData = nouveau_bufferobj_get_subdata; 181 functions->MapBufferRange = nouveau_bufferobj_map_range; 182 functions->UnmapBuffer = nouveau_bufferobj_unmap; 183} 184