Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / drivers / dri / intel / intel_buffer_objects.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include "main/imports.h"
30 #include "main/mtypes.h"
31 #include "main/bufferobj.h"
32
33 #include "intel_context.h"
34 #include "intel_buffer_objects.h"
35 #include "intel_batchbuffer.h"
36 #include "intel_regions.h"
37
38 static GLboolean
39 intel_bufferobj_unmap(GLcontext * ctx,
40 GLenum target, struct gl_buffer_object *obj);
41
42 /** Allocates a new dri_bo to store the data for the buffer object. */
43 static void
44 intel_bufferobj_alloc_buffer(struct intel_context *intel,
45 struct intel_buffer_object *intel_obj)
46 {
47 intel_obj->buffer = dri_bo_alloc(intel->bufmgr, "bufferobj",
48 intel_obj->Base.Size, 64);
49 }
50
51 /**
52 * There is some duplication between mesa's bufferobjects and our
53 * bufmgr buffers. Both have an integer handle and a hashtable to
54 * lookup an opaque structure. It would be nice if the handles and
55 * internal structure where somehow shared.
56 */
57 static struct gl_buffer_object *
58 intel_bufferobj_alloc(GLcontext * ctx, GLuint name, GLenum target)
59 {
60 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
61
62 _mesa_initialize_buffer_object(&obj->Base, name, target);
63
64 obj->buffer = NULL;
65
66 return &obj->Base;
67 }
68
69 /* Break the COW tie to the region. The region gets to keep the data.
70 */
71 void
72 intel_bufferobj_release_region(struct intel_context *intel,
73 struct intel_buffer_object *intel_obj)
74 {
75 assert(intel_obj->region->buffer == intel_obj->buffer);
76 intel_obj->region->pbo = NULL;
77 intel_obj->region = NULL;
78
79 dri_bo_unreference(intel_obj->buffer);
80 intel_obj->buffer = NULL;
81 }
82
83 /* Break the COW tie to the region. Both the pbo and the region end
84 * up with a copy of the data.
85 */
86 void
87 intel_bufferobj_cow(struct intel_context *intel,
88 struct intel_buffer_object *intel_obj)
89 {
90 assert(intel_obj->region);
91 intel_region_cow(intel, intel_obj->region);
92 }
93
94
95 /**
96 * Deallocate/free a vertex/pixel buffer object.
97 * Called via glDeleteBuffersARB().
98 */
99 static void
100 intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj)
101 {
102 struct intel_context *intel = intel_context(ctx);
103 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
104
105 assert(intel_obj);
106
107 /* Buffer objects are automatically unmapped when deleting according
108 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
109 * (though it does if you call glDeleteBuffers)
110 */
111 if (obj->Pointer)
112 intel_bufferobj_unmap(ctx, 0, obj);
113
114 _mesa_free(intel_obj->sys_buffer);
115 if (intel_obj->region) {
116 intel_bufferobj_release_region(intel, intel_obj);
117 }
118 else if (intel_obj->buffer) {
119 dri_bo_unreference(intel_obj->buffer);
120 }
121
122 _mesa_free(intel_obj);
123 }
124
125
126
127 /**
128 * Allocate space for and store data in a buffer object. Any data that was
129 * previously stored in the buffer object is lost. If data is NULL,
130 * memory will be allocated, but no copy will occur.
131 * Called via glBufferDataARB().
132 */
133 static void
134 intel_bufferobj_data(GLcontext * ctx,
135 GLenum target,
136 GLsizeiptrARB size,
137 const GLvoid * data,
138 GLenum usage, struct gl_buffer_object *obj)
139 {
140 struct intel_context *intel = intel_context(ctx);
141 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
142
143 intel_obj->Base.Size = size;
144 intel_obj->Base.Usage = usage;
145
146 assert(!obj->Pointer); /* Mesa should have unmapped it */
147
148 if (intel_obj->region)
149 intel_bufferobj_release_region(intel, intel_obj);
150
151 if (intel_obj->buffer != NULL) {
152 dri_bo_unreference(intel_obj->buffer);
153 intel_obj->buffer = NULL;
154 }
155 _mesa_free(intel_obj->sys_buffer);
156 intel_obj->sys_buffer = NULL;
157
158 if (size != 0) {
159 #ifdef I915
160 /* On pre-965, stick VBOs in system memory, as we're always doing swtnl
161 * with their contents anyway.
162 */
163 if (target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER) {
164 intel_obj->sys_buffer = _mesa_malloc(size);
165 if (intel_obj->sys_buffer != NULL) {
166 if (data != NULL)
167 memcpy(intel_obj->sys_buffer, data, size);
168 return;
169 }
170 }
171 #endif
172 intel_bufferobj_alloc_buffer(intel, intel_obj);
173
174 if (data != NULL)
175 dri_bo_subdata(intel_obj->buffer, 0, size, data);
176 }
177 }
178
179
180 /**
181 * Replace data in a subrange of buffer object. If the data range
182 * specified by size + offset extends beyond the end of the buffer or
183 * if data is NULL, no copy is performed.
184 * Called via glBufferSubDataARB().
185 */
186 static void
187 intel_bufferobj_subdata(GLcontext * ctx,
188 GLenum target,
189 GLintptrARB offset,
190 GLsizeiptrARB size,
191 const GLvoid * data, struct gl_buffer_object *obj)
192 {
193 struct intel_context *intel = intel_context(ctx);
194 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
195
196 assert(intel_obj);
197
198 if (intel_obj->region)
199 intel_bufferobj_cow(intel, intel_obj);
200
201 if (intel_obj->sys_buffer)
202 memcpy((char *)intel_obj->sys_buffer + offset, data, size);
203 else
204 dri_bo_subdata(intel_obj->buffer, offset, size, data);
205 }
206
207
208 /**
209 * Called via glGetBufferSubDataARB().
210 */
211 static void
212 intel_bufferobj_get_subdata(GLcontext * ctx,
213 GLenum target,
214 GLintptrARB offset,
215 GLsizeiptrARB size,
216 GLvoid * data, struct gl_buffer_object *obj)
217 {
218 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
219
220 assert(intel_obj);
221 dri_bo_get_subdata(intel_obj->buffer, offset, size, data);
222 }
223
224
225
226 /**
227 * Called via glMapBufferARB().
228 */
229 static void *
230 intel_bufferobj_map(GLcontext * ctx,
231 GLenum target,
232 GLenum access, struct gl_buffer_object *obj)
233 {
234 struct intel_context *intel = intel_context(ctx);
235 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
236 GLboolean read_only = (access == GL_READ_ONLY_ARB);
237 GLboolean write_only = (access == GL_WRITE_ONLY_ARB);
238
239 assert(intel_obj);
240
241 if (intel_obj->sys_buffer) {
242 obj->Pointer = intel_obj->sys_buffer;
243 return obj->Pointer;
244 }
245
246 if (intel_obj->region)
247 intel_bufferobj_cow(intel, intel_obj);
248
249 if (intel_obj->buffer == NULL) {
250 obj->Pointer = NULL;
251 return NULL;
252 }
253
254 if (write_only && intel->intelScreen->kernel_exec_fencing) {
255 drm_intel_gem_bo_map_gtt(intel_obj->buffer);
256 intel_obj->mapped_gtt = GL_TRUE;
257 } else {
258 drm_intel_bo_map(intel_obj->buffer, !read_only);
259 intel_obj->mapped_gtt = GL_FALSE;
260 }
261
262 obj->Pointer = intel_obj->buffer->virtual;
263 return obj->Pointer;
264 }
265
266
267 /**
268 * Called via glMapBufferARB().
269 */
270 static GLboolean
271 intel_bufferobj_unmap(GLcontext * ctx,
272 GLenum target, struct gl_buffer_object *obj)
273 {
274 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
275
276 assert(intel_obj);
277 if (intel_obj->buffer != NULL) {
278 assert(obj->Pointer);
279 if (intel_obj->mapped_gtt) {
280 drm_intel_gem_bo_unmap_gtt(intel_obj->buffer);
281 } else {
282 drm_intel_bo_unmap(intel_obj->buffer);
283 }
284 obj->Pointer = NULL;
285 }
286 return GL_TRUE;
287 }
288
289 dri_bo *
290 intel_bufferobj_buffer(struct intel_context *intel,
291 struct intel_buffer_object *intel_obj, GLuint flag)
292 {
293 if (intel_obj->region) {
294 if (flag == INTEL_WRITE_PART)
295 intel_bufferobj_cow(intel, intel_obj);
296 else if (flag == INTEL_WRITE_FULL) {
297 intel_bufferobj_release_region(intel, intel_obj);
298 intel_bufferobj_alloc_buffer(intel, intel_obj);
299 }
300 }
301
302 if (intel_obj->buffer == NULL) {
303 void *sys_buffer = intel_obj->sys_buffer;
304
305 /* only one of buffer and sys_buffer could be non-NULL */
306 intel_bufferobj_alloc_buffer(intel, intel_obj);
307 intel_obj->sys_buffer = NULL;
308
309 intel_bufferobj_subdata(&intel->ctx,
310 GL_ARRAY_BUFFER_ARB,
311 0,
312 intel_obj->Base.Size,
313 sys_buffer,
314 &intel_obj->Base);
315 _mesa_free(sys_buffer);
316 intel_obj->sys_buffer = NULL;
317 }
318
319 return intel_obj->buffer;
320 }
321
322 void
323 intelInitBufferObjectFuncs(struct dd_function_table *functions)
324 {
325 functions->NewBufferObject = intel_bufferobj_alloc;
326 functions->DeleteBuffer = intel_bufferobj_free;
327 functions->BufferData = intel_bufferobj_data;
328 functions->BufferSubData = intel_bufferobj_subdata;
329 functions->GetBufferSubData = intel_bufferobj_get_subdata;
330 functions->MapBuffer = intel_bufferobj_map;
331 functions->UnmapBuffer = intel_bufferobj_unmap;
332 }