1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 2009 VMware, Inc. All Rights Reserved.
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL VMWARE BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
29 // tbufferobject.c - test various buffer object features/extensions
33 #define GL_GLEXT_PROTOTYPES
38 #include "tbufferobject.h"
44 // GL_ARB_vertex/fragment_program
45 static PFNGLGENBUFFERSARBPROC glGenBuffersARB_func
= NULL
;
46 static PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB_func
= NULL
;
47 static PFNGLBINDBUFFERARBPROC glBindBufferARB_func
= NULL
;
48 static PFNGLBUFFERDATAARBPROC glBufferDataARB_func
= NULL
;
49 static PFNGLMAPBUFFERARBPROC glMapBufferARB_func
= NULL
;
50 static PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB_func
= NULL
;
53 static PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData_func
= NULL
;
55 // GL_ARB_map_buffer_range
56 static PFNGLMAPBUFFERRANGEPROC glMapBufferRange_func
= NULL
;
57 static PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange_func
= NULL
;
60 BufferObjectResult::BufferObjectResult()
67 BufferObjectTest::setup(void)
69 have_ARB_vertex_buffer_object
= GLUtils::haveExtension("GL_ARB_vertex_buffer_object");
70 have_ARB_pixel_buffer_object
= GLUtils::haveExtension("GL_ARB_pixel_buffer_object");
71 have_ARB_copy_buffer
= GLUtils::haveExtension("GL_ARB_copy_buffer");
72 have_ARB_map_buffer_range
= GLUtils::haveExtension("GL_ARB_map_buffer_range");
74 if (have_ARB_vertex_buffer_object
) {
75 target1
= GL_ARRAY_BUFFER_ARB
;
76 target2
= GL_ELEMENT_ARRAY_BUFFER_ARB
;
78 else if (have_ARB_pixel_buffer_object
) {
79 target1
= GL_PIXEL_PACK_BUFFER_ARB
;
80 target2
= GL_PIXEL_UNPACK_BUFFER_ARB
;
87 glGenBuffersARB_func
= (PFNGLGENBUFFERSARBPROC
) GLUtils::getProcAddress("glGenBuffersARB");
88 glDeleteBuffersARB_func
= (PFNGLDELETEBUFFERSARBPROC
) GLUtils::getProcAddress("glDeleteBuffersARB");
89 glBindBufferARB_func
= (PFNGLBINDBUFFERARBPROC
) GLUtils::getProcAddress("glBindBufferARB");
90 glBufferDataARB_func
= (PFNGLBUFFERDATAARBPROC
) GLUtils::getProcAddress("glBufferDataARB");
91 glMapBufferARB_func
= (PFNGLMAPBUFFERARBPROC
) GLUtils::getProcAddress("glMapBufferARB");
92 glUnmapBufferARB_func
= (PFNGLUNMAPBUFFERARBPROC
) GLUtils::getProcAddress("glUnmapBufferARB");
94 if (have_ARB_copy_buffer
) {
95 glCopyBufferSubData_func
= (PFNGLCOPYBUFFERSUBDATAPROC
) GLUtils::getProcAddress("glCopyBufferSubData");
98 if (have_ARB_map_buffer_range
) {
99 glMapBufferRange_func
= (PFNGLMAPBUFFERRANGEPROC
) GLUtils::getProcAddress("glMapBufferRange");
100 glFlushMappedBufferRange_func
= (PFNGLFLUSHMAPPEDBUFFERRANGEPROC
) GLUtils::getProcAddress("glFlushMappedBufferRange");
107 // test GL_ARB_copy_buffer
109 BufferObjectTest::testCopyBuffer(void)
111 static const GLsizei size1
= 4200, size2
= 3800;
112 GLubyte buf1
[size1
], buf2
[size2
];
118 glGenBuffersARB_func(2, bufs
);
120 // setup first buffer
121 glBindBufferARB_func(target1
, bufs
[0]);
122 glBufferDataARB_func(target1
, size1
, NULL
, GL_STATIC_DRAW
);
123 map
= (GLubyte
*) glMapBufferARB_func(target1
, GL_WRITE_ONLY_ARB
);
124 for (i
= 0; i
< size1
; i
++) {
125 map
[i
] = buf1
[i
] = i
& 0xff;
127 glUnmapBufferARB_func(target1
);
129 // setup second buffer
130 glBindBufferARB_func(target2
, bufs
[1]);
131 glBufferDataARB_func(target2
, size2
, NULL
, GL_STATIC_DRAW
);
132 map
= (GLubyte
*) glMapBufferARB_func(target2
, GL_WRITE_ONLY_ARB
);
133 for (i
= 0; i
< size2
; i
++) {
134 map
[i
] = buf2
[i
] = 0;
136 glUnmapBufferARB_func(target2
);
138 // copy random sections of first buffer to second buffer
139 for (i
= 0; i
< 50; i
++) {
140 const int min
= size1
< size2
? size1
: size2
;
141 int size
= rand
.next() % min
;
142 int srcOffset
= rand
.next() % (size1
- size
);
143 int dstOffset
= rand
.next() % (size2
- size
);
145 assert(srcOffset
+ size
<= size1
);
146 assert(dstOffset
+ size
<= size2
);
148 // test copy from first buffer to second
149 glCopyBufferSubData_func(target1
, // src target
150 target2
, // dst target
151 srcOffset
, // src start
152 dstOffset
, // dst start
155 // update the validation/reference buffer in the same way
156 memcpy(buf2
+ dstOffset
, buf1
+ srcOffset
, size
);
159 // no errors should have been generated.
161 env
->log
<< "Unexpected GL error in copy buffer test.\n";
165 // check results in second buffer object
166 map
= (GLubyte
*) glMapBufferARB_func(target2
, GL_READ_ONLY_ARB
);
168 for (i
= 0; i
< size2
; i
++) {
169 if (map
[i
] != buf2
[i
]) {
170 printf("%d: %d != %d\n", i
, map
[i
], buf2
[i
]);
175 glUnmapBufferARB_func(target2
);
177 glDeleteBuffersARB_func(2, bufs
);
183 // Test GL_ARB_map_buffer_range
184 // This isn't exhaustive, but covers the basics.
186 BufferObjectTest::testMapBufferRange(void)
188 static const GLsizei size
= 30000;
196 glGenBuffersARB_func(1, &buffer
);
197 glBindBufferARB_func(target1
, buffer
);
198 glBufferDataARB_func(target1
, size
, NULL
, GL_STATIC_DRAW
);
200 // initialize to zeros
201 map
= (GLubyte
*) glMapBufferRange_func(target1
, 0, size
, GL_MAP_WRITE_BIT
);
202 for (i
= 0; i
< size
; i
++) {
205 glUnmapBufferARB_func(target1
);
207 // write to random ranges
208 for (i
= 0; i
< 50; i
++) {
209 const int mapSize
= rand
.next() % size
;
210 const int mapOffset
= rand
.next() % (size
- mapSize
);
212 assert(mapOffset
+ mapSize
<= size
);
215 glMapBufferRange_func(target1
, mapOffset
, mapSize
,
216 GL_MAP_WRITE_BIT
| GL_MAP_FLUSH_EXPLICIT_BIT
);
218 for (j
= 0; j
< mapSize
; j
++) {
219 map
[j
] = buf
[mapOffset
+ j
] = (mapOffset
+ j
) & 0xff;
222 glFlushMappedBufferRange_func(target1
, 0, mapSize
);
224 glUnmapBufferARB_func(target1
);
230 // read/check random ranges
231 for (i
= 0; i
< 50 && pass
; i
++) {
232 const int mapSize
= rand
.next() % size
;
233 const int mapOffset
= rand
.next() % (size
- mapSize
);
235 assert(mapOffset
+ mapSize
<= size
);
237 map
= (GLubyte
*) glMapBufferRange_func(target1
, mapOffset
,
238 mapSize
, GL_MAP_READ_BIT
);
240 for (j
= 0; j
< mapSize
; j
++) {
241 if (map
[j
] != buf
[mapOffset
+ j
]) {
246 glUnmapBufferARB_func(target1
);
249 glDeleteBuffersARB_func(1, &buffer
);
259 BufferObjectTest::runOne(BufferObjectResult
&r
, Window
&w
)
261 (void) w
; // silence warning
265 // if neither GL_ARB_vertex/pixel_buffer_object are supported, do nothing
270 if (r
.pass
&& have_ARB_copy_buffer
)
271 r
.pass
= testCopyBuffer();
273 if (r
.pass
&& have_ARB_map_buffer_range
)
274 r
.pass
= testMapBufferRange();
279 BufferObjectTest::logOne(BufferObjectResult
&r
)
287 BufferObjectTest::compareOne(BufferObjectResult
&oldR
,
288 BufferObjectResult
&newR
)
290 comparePassFail(oldR
, newR
);
295 BufferObjectResult::putresults(ostream
&s
) const
307 BufferObjectResult::getresults(istream
&s
)
312 if (strcmp(result
, "FAIL") == 0) {
322 // The test object itself:
323 BufferObjectTest
bufferObjectTest("bufferObject",
325 "", // no extension tests
326 "Test buffer object features and extensions such as:\n"
327 " GL_ARB_vertex_buffer_object\n"
328 " GL_ARB_pixel_buffer_object\n"
329 " GL_ARB_copy_buffer\n"
330 " GL_ARB_map_buffer_range\n");