16c64d30284f4a6923213d48212f8ba2f2070543
[glmemperf] / cpuinterleavingtest.cpp
1 /**
2  * OpenGL ES 2.0 memory performance estimator
3  * Copyright (C) 2009 Nokia
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * \author Sami Kyöstilä <sami.kyostila@nokia.com>
20  *
21  * CPU texture streaming test
22  */
23 #include "cpuinterleavingtest.h"
24 #include "util.h"
25 #include "native.h"
26 #include <sstream>
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/extensions/XShm.h>
30 #include <sys/ipc.h>
31 #include <sys/shm.h>
32
33 template <typename TYPE>
34 void fillTexture(TYPE* pixels, int width, int height, int stride, int frame)
35 {
36     TYPE color = (TYPE)0xffffffffu;
37     for (int y = 0; y < height; y++)
38     {
39         for (int x = 0; x < width; x++)
40         {
41             if ((x + y + frame) & 0x10)
42             {
43                 pixels[x] = color;
44             }
45             else
46             {
47                 pixels[x] = 0;
48             }
49         }
50         pixels += stride / sizeof(TYPE);
51     }
52 }
53
54 CPUInterleavingTest::CPUInterleavingTest(CPUInterleavingMethod method,
55                                          int buffers, int bitsPerPixel,
56                                          int width, int height,
57                                          float texW, float texH):
58     BlitTest(width, height, false, texW, texH),
59     m_method(method),
60     m_buffers(buffers),
61     m_dataBitsPerPixel(bitsPerPixel),
62     m_readBuffer(buffers - 1),
63     m_writeBuffer(0)
64 {
65 }
66
67
68 void CPUInterleavingTest::prepare()
69 {
70     int i;
71     bool success;
72
73     BlitTest::prepare();
74
75     glGenTextures(m_buffers, m_textures);
76     for (int i = 0; i < m_buffers; i++)
77     {
78         glBindTexture(GL_TEXTURE_2D, m_textures[i]);
79         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
80         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
81     }
82
83     ASSERT_GL();
84
85     switch (m_method)
86     {
87     case CPUI_TEXTURE_UPLOAD:
88         {
89             m_dataStride = m_width * m_dataBitsPerPixel / 8;
90             for (i = 0; i < m_buffers; i++)
91             {
92                 m_textureData[i] = new char[m_height * m_dataStride];
93             }
94         }
95         break;
96     case CPUI_XSHM_IMAGE:
97         {
98             Status shmSupported = XShmQueryExtension(ctx.nativeDisplay);
99             if (!shmSupported)
100             {
101                 fail("X11 shared memory extension not supported");
102             }
103
104             m_completionEvent = XShmGetEventBase(ctx.nativeDisplay) + ShmCompletion;
105
106             const EGLint pixmapConfigAttrs[] =
107             {
108                 EGL_BUFFER_SIZE, m_dataBitsPerPixel,
109                 EGL_NONE
110             };
111             EGLint configCount = 0;
112
113             eglChooseConfig(ctx.dpy, pixmapConfigAttrs, &m_config, 1, &configCount);
114             assert(configCount);
115
116             for (i = 0; i < m_buffers; i++)
117             {
118                 success = nativeCreatePixmap(ctx.nativeDisplay, ctx.dpy,
119                                              m_config, m_width, m_height, &m_pixmaps[i]);
120                 assert(success);
121
122                 XGCValues gcValues;
123                 m_gc[i] = XCreateGC(ctx.nativeDisplay, m_pixmaps[i], 0, &gcValues);
124
125                 const EGLint surfAttrs[] =
126                 {
127                     EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
128                     EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
129                     EGL_MIPMAP_TEXTURE, EGL_FALSE,
130                     EGL_NONE
131                 };
132
133                 m_surfaces[i] = eglCreatePixmapSurface(ctx.dpy, m_config, m_pixmaps[i], surfAttrs);
134                 assert(m_surfaces[i] != EGL_NO_SURFACE);
135
136                 glBindTexture(GL_TEXTURE_2D, m_textures[i]);
137                 success = eglBindTexImage(ctx.dpy, m_surfaces[i], EGL_BACK_BUFFER);
138                 assert(success);
139                 
140                 XVisualInfo visualInfo;
141                 XVisualInfo* visual;
142                 int visualCount = 0;
143                 visualInfo.depth = m_dataBitsPerPixel;
144                 visualInfo.screen = DefaultScreen(ctx.nativeDisplay);
145                 visual = XGetVisualInfo(ctx.nativeDisplay, VisualDepthMask | VisualScreenMask, 
146                                         &visualInfo, &visualCount);
147
148                 assert(visualCount > 0);
149
150                 m_ximage[i] = XShmCreateImage(ctx.nativeDisplay, visual->visual, m_dataBitsPerPixel,
151                                               ZPixmap, NULL,
152                                               &m_shminfo[i], m_width, m_height);
153                 m_shminfo[i].shmid = shmget(IPC_PRIVATE, 
154                                             m_ximage[i]->bytes_per_line *
155                                             m_ximage[i]->height, IPC_CREAT | 0777);
156                 m_shminfo[i].shmaddr = m_ximage[i]->data = (char*)shmat(m_shminfo[i].shmid, 0, 0);
157                 assert(m_shminfo[i].shmaddr);
158                 m_shminfo[i].readOnly = False;
159                 Status status = XShmAttach(ctx.nativeDisplay, &m_shminfo[i]);
160                 assert(status);
161
162                 m_textureData[i] = m_ximage[i]->data;
163                 m_dataStride = m_ximage[i]->bytes_per_line;
164                 m_writeCompleted[i] = true;
165                 m_drawableIndex[m_pixmaps[i]] = i;
166             }
167         }
168         break;
169     default:
170         assert(0);
171         return;
172     }
173 }
174
175 void CPUInterleavingTest::teardown()
176 {
177     int i;
178     glDeleteTextures(m_buffers, m_textures);
179
180     switch (m_method)
181     {
182     case CPUI_TEXTURE_UPLOAD:
183         {
184             for (i = 0; i < m_buffers; i++)
185             {
186                 delete[] m_textureData[i];
187             }
188         }
189         break;
190     case CPUI_XSHM_IMAGE:
191         {
192             for (i = 0; i < m_buffers; i++)
193             {
194                 XShmDetach(ctx.nativeDisplay, &m_shminfo[i]);
195                 XDestroyImage(m_ximage[i]);
196                 shmdt(m_shminfo[i].shmaddr);
197                 shmctl(m_shminfo[i].shmid, IPC_RMID, 0);
198
199                 eglReleaseTexImage(ctx.dpy, m_surfaces[i], EGL_BACK_BUFFER);
200                 eglDestroySurface(ctx.dpy, m_surfaces[i]);
201                 nativeDestroyPixmap(ctx.nativeDisplay, m_pixmaps[i]);
202                 XFreeGC(ctx.nativeDisplay, m_gc[i]);
203             }
204         }
205         break;
206     default:
207         assert(0);
208         return;
209     }
210
211     BlitTest::teardown();
212 }
213
214 std::string CPUInterleavingTest::name() const
215 {
216     std::stringstream s;
217
218     s << "blit_cpu_";
219
220     switch (m_method)
221     {
222     case CPUI_TEXTURE_UPLOAD:
223         s << "texupload";
224         break;
225     case CPUI_XSHM_IMAGE:
226         s << "shmimage";
227         break;
228     case CPUI_IMG_TEXTURE_STREAMING:
229         s << "texstream";
230         break;
231     case CPUI_PIXEL_BUFFER_OBJECT:
232         s << "pbo";
233         break;
234     case CPUI_EGL_LOCK_SURFACE:
235         s << "locksurf";
236         break;
237     }
238
239     switch (m_dataBitsPerPixel)
240     {
241     case 16:
242         s << "_16bpp";
243         break;
244     case 32:
245         s << "_32bpp";
246         break;
247     }
248
249     s << "_" << m_buffers << "x" << m_width << "x" << m_height;
250
251     return s.str();
252 }
253
254 void CPUInterleavingTest::operator()(int frame)
255 {
256     switch (m_dataBitsPerPixel)
257     {
258     case 16:
259         fillTexture(reinterpret_cast<uint16_t*>(m_textureData[m_writeBuffer]),
260                     m_width, m_height, m_dataStride, frame);
261         break;
262     case 32:
263         fillTexture(reinterpret_cast<uint32_t*>(m_textureData[m_writeBuffer]),
264                     m_width, m_height, m_dataStride, frame);
265         break;
266     }
267
268     glBindTexture(GL_TEXTURE_2D, m_textures[m_writeBuffer]);
269
270     switch (m_method)
271     {
272     case CPUI_TEXTURE_UPLOAD:
273         if (m_dataBitsPerPixel == 32)
274         {
275             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0,
276                          GL_RGBA, GL_UNSIGNED_BYTE, m_textureData[m_writeBuffer]);
277         }
278         else
279         {
280             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0,
281                          GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_textureData[m_writeBuffer]);
282         }
283         break;
284     case CPUI_XSHM_IMAGE:
285         {
286             // Wait for the completion event for this buffer
287             while (XEventsQueued(ctx.nativeDisplay, QueuedAfterReading) > 0 ||
288                    !m_writeCompleted[m_writeBuffer])
289             {
290                 XEvent event;
291                 XNextEvent(ctx.nativeDisplay, &event);
292                 if (event.type == m_completionEvent)
293                 {
294                     XShmCompletionEvent* e = reinterpret_cast<XShmCompletionEvent*>(&event);
295                     int i = m_drawableIndex[e->drawable];
296                     m_writeCompleted[i] = true;
297                 }
298             }
299             XShmPutImage(ctx.nativeDisplay, m_pixmaps[m_writeBuffer], m_gc[m_writeBuffer],
300                          m_ximage[m_writeBuffer], 0, 0, 0, 0, m_width, m_height, True);
301             m_writeCompleted[m_writeBuffer] = false;
302         }
303         break;
304     default:
305         assert(0);
306         break;
307     }
308
309     glBindTexture(GL_TEXTURE_2D, m_textures[m_readBuffer]);
310     m_writeBuffer = (m_writeBuffer + 1) % m_buffers;
311     m_readBuffer  = (m_readBuffer  + 1) % m_buffers;
312
313     BlitTest::operator()(frame);
314 }