今回はWayland EGLの環境で、前回の四面体を表示してみました。
WaylandはXに変わるディスプレイサーバで、以下の記事でFedora25(デフォルトでサポート)上でテストしました。
ここでは、Ubuntu 16.04を使います。(インストールメモを忘れてしましまたが、下にあるコンパイルオプションからだいたい想像できると思います)
参考 :
http://blog.techlab-xe.net/archives/4637
https://github.com/techlabxe/SimpleWindowWayland/tree/base-1.1
こちらのサイトを参考にさせていただきました。
カメラが自動的移動する処理はそのままで、四面体を表示させ色をつけています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <cmath> #include <cstdint> #include <vector> #include <GLES2/gl2.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/matrix_transform.hpp> #include "WaylandCore.h" #define WIDTH 640 #define HEIGHT 480 #define TITLE "Wayland EGL Window" const GLchar* srcVertexShader[] = { "attribute vec4 vPosition;\n" "attribute vec3 vColor;\n" "varying vec4 color;\n" "uniform vec4 matPVW[4];\n" "void main() {\n" "vec4 pos;\n" "pos = matPVW[0] * vPosition.x;\n" "pos += matPVW[1]* vPosition.y;\n" "pos += matPVW[2]* vPosition.z;\n" "pos += matPVW[3]* vPosition.w;\n" "gl_Position = pos;\n" "color.rgb = vec3(vColor.r, vColor.g, vColor.b);\n" "color.a = 1.0;\n" "}" }; const GLchar* srcFragmentShader[] = { "precision mediump float; \n" "varying vec4 color;\n" "void main() {\n" "gl_FragColor = color;\n" "}" }; struct DrawBatch { GLuint vb, ib; GLuint shader; int indexCount; } drawObj; struct VertexPosition { float x, y, z; }; struct VertexColor { float r, g, b; }; struct Vertex { VertexPosition Position; VertexColor Color; }; GLint attrPVW; GLuint createShaderProgram(const char* srcVS[], const char* srcFS[]){ GLuint shaderVS = glCreateShader(GL_VERTEX_SHADER); GLuint shaderFS = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shaderVS, 1, srcVS, NULL); glCompileShader(shaderVS); glShaderSource(shaderFS, 1, srcFS, NULL); glCompileShader(shaderFS); GLuint program; program = glCreateProgram(); glAttachShader(program, shaderVS); glAttachShader(program, shaderFS); glLinkProgram(program); return program; } template<typename T> GLuint createBufferObject(std::vector<T>& src, GLuint type) { GLuint vbo; glGenBuffers( 1, &vbo ); glBindBuffer( type, vbo ); glBufferData( type, sizeof(T) * src.size(), src.data(), GL_STATIC_DRAW ); return vbo; } void createResource() { drawObj.shader = createShaderProgram( srcVertexShader, srcFragmentShader ); GLint attrPos = glGetAttribLocation( drawObj.shader, "vPosition" ); GLint attrCol = glGetAttribLocation( drawObj.shader, "vColor" ); attrPVW = glGetUniformLocation( drawObj.shader, "matPVW" ); std::vector<uint16_t> indices = {0,1,2,1,2,3,0,2,3,0,1,3}; std::vector<Vertex> vertices; GLfloat vData[] = { -1.0f, -1.0f, 0.0f, //1 1.0f, -1.0f, 0.0f, //2 0.0f, 1.0f, 0.0f, //3 0.0f, 0.0f, 1.0f, //4 }; GLfloat vColor[] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, }; for(int i=0;i<4;i++){ Vertex v; v.Position.x = vData[i*3]; v.Position.y = vData[i*3+1]; v.Position.z = vData[i*3+2]; v.Color.r = vColor[i*3]; v.Color.g = vColor[i*3+1]; v.Color.b = vColor[i*3+2]; vertices.push_back(v); } drawObj.vb = createBufferObject(vertices, GL_ARRAY_BUFFER); drawObj.ib = createBufferObject(indices, GL_ELEMENT_ARRAY_BUFFER); drawObj.indexCount = indices.size(); char* offset = NULL; int stride = sizeof(Vertex); glVertexAttribPointer(attrPos, 3, GL_FLOAT, GL_FALSE, stride, offset); offset += sizeof(VertexPosition); glVertexAttribPointer(attrCol, 3, GL_FLOAT, GL_FALSE, stride, offset); offset += sizeof(VertexColor); glEnableVertexAttribArray(attrPos); glEnableVertexAttribArray(attrCol); } void destroyResource() { glDeleteBuffers( 1, &drawObj.vb ); glDeleteBuffers( 1, &drawObj.ib ); glDeleteProgram( drawObj.shader ); } void draw() { static double angle = 0.0f; angle += .01f; if( angle > 3600.0 ) { angle -= 3600.0; } glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::vec3 cameraPos = glm::vec3(0.0, 0.0f, 2.0f); glm::mat4 proj = glm::perspective<float>(30.0f, float(WIDTH)/float(HEIGHT), 1.0f, 100.0f); glm::mat4 view = glm::lookAt<float>(cameraPos, glm::vec3(0.0f,0.0f,0.0f), glm::vec3(0.0f,1.0f,0.0f)); glm::mat4 world= glm::rotate( glm::mat4(1.0f), (float)angle, glm::vec3(0.0f,0.0f,1.0f)); world= glm::rotate(world, (float) angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f)); world= glm::rotate(world, (float) angle * 0.5f, glm::vec3(1.0f, 0.0f, 0.0f)); glUseProgram(drawObj.shader); glm::mat4 pvw = proj * view * world; glUniform4fv(attrPVW, 4, glm::value_ptr(pvw)); glBindBuffer(GL_ARRAY_BUFFER, drawObj.vb); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawObj.ib); glDrawElements(GL_TRIANGLES, drawObj.indexCount, GL_UNSIGNED_SHORT, NULL); } int main() { WaylandCore* core = new WaylandCore(WIDTH, HEIGHT, TITLE); fprintf(stderr, "Renderer: %s\n", (char*)glGetString(GL_RENDERER)); fprintf(stderr, "GL_VERSION: %s\n", (char*)glGetString( GL_VERSION)); fprintf(stderr, "GL_EXTENSIONS: %s\n", (char*)glGetString(GL_EXTENSIONS)); createResource(); while( !core->isShouldClose() ) { core->pollEvents(); usleep(100*1000); glClearColor( 0, 0, 0.25f, 0.75f ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); draw(); core->swapBuffers(); } destroyResource(); delete core;core = NULL; return 0; } |
g++ -o WaylandEglTest main.cpp WaylandCore.cpp WaylandCore_registry_handlers.cpp WaylandCore_seat_handlers.cpp -lwayland-client -lwayland-cursor -lwayland-egl -lEGL -lGLESv2 -std=c++11
main.cpp以外のWayland部分は、上記サイトにあるのを使わせていただきました。
(マウスやキーボードのイベントリスナーなども含んでいます)
参考までに、メインループの最初と最後にあるpollEvents()とswapBuffers()をWaylandCore.cppから抜粋。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
void WaylandCore::pollEvents() { if( mDisplay == NULL || mRegistry == NULL ) { mShouldClose = true; return; } pollfd fds[] = { { wl_display_get_fd(mDisplay), POLLIN }, }; while( wl_display_prepare_read(mDisplay) != 0 ) { wl_display_dispatch_pending(mDisplay); } wl_display_flush(mDisplay); if( poll(fds,1,0) > 0 ) { wl_display_read_events(mDisplay); wl_display_dispatch_pending(mDisplay); } else { wl_display_cancel_read(mDisplay); } } void WaylandCore::swapBuffers() { eglSwapBuffers( mEglDisplay, mSurface.eglSurface ); } |
イベントのポーリングでソケット読み込みしています。IPC(Interprocess Communication)の部分が詳しく書かれています。OpneGLもそうですが、コードボリュームが多くなってしまうのは、このような細かいAPI(wl_xxx)を組みあわせるところから書くからでしょう。意味がわかれば中身を意識せず使えばいいと思われます。
(この部分、Xのようにリモートでアクセスできるかどうか、興味は膨らみます)
ここまで違う環境でシェーダープログラムを試してみると、理解がより深まった気がします。
いろいろな環境で実行できるとわかったところで、GPUの特性を生かした画像処理のシェーダプログラムにもっと比重をおいて学習したいと思います。
Renderer: Gallium 0.4 on llvmpipe(LLVM3.8, 256bits)
GL Version : OpenGL ES 3.0 Mesa 12.0.6
EGL major : 1 minor : 4