1 module Engine.Buffer; 2 3 import derelict.opengl3.gl; 4 import gl3n.linalg; 5 import std.stdio; 6 import Engine.Options; 7 8 class Buffer { 9 GLenum type; 10 GLenum memtype; 11 GLenum buffer; 12 13 int size; 14 15 alias buffer this; 16 17 this(T)(T[] arr, GLenum type, GLenum memtype) { 18 glGenBuffers(1, &buffer); 19 glBindBuffer(type, buffer); 20 glBufferData(type, T.sizeof * arr.length, &arr[0], memtype); 21 22 this.type = type; 23 this.memtype = memtype; 24 this.size = T.sizeof * arr.length; 25 } 26 27 this()(int size, GLenum type, GLenum memtype) { 28 glGenBuffers(1, &buffer); 29 glBindBuffer(type, buffer); 30 glBufferData(type, size, null, memtype); 31 32 this.type = type; 33 this.memtype = memtype; 34 this.size = size; 35 } 36 37 this()(long size, GLenum type, GLenum memtype) { 38 this(cast(int)size, type, memtype); 39 } 40 41 final void Resize(long size) { 42 Resize(cast(int)size); 43 } 44 45 final void Resize(int size) { 46 this.size = size; 47 glBindBuffer(type, buffer); 48 glBufferData(type, size, null, memtype); 49 } 50 51 final void Bind()() { 52 glBindBuffer(type, buffer); 53 } 54 55 final void Unbind()() { 56 glBindBuffer(type, 0); 57 } 58 59 void Update(T)(T[] arr, int offset = 0) 60 { 61 if (T.sizeof * arr.length + offset * T.sizeof > size) { 62 throw new Exception("array type is too big for this buffer"); 63 } 64 65 Bind(); 66 glBufferSubData(type, offset * T.sizeof, T.sizeof * arr.length, &arr[0]); 67 } 68 69 void Update(T)(void delegate(T[] arr) update) { 70 auto arr = Map!T(); 71 scope( exit ) Unmap(); 72 update(arr); 73 } 74 75 T[] Map(T)(size_t offset, size_t len) { 76 Bind(); 77 // map the buffer object into client's memory 78 // Note that glMapBufferARB() causes sync issue. 79 // If GPU is working with this buffer, glMapBufferARB() will wait(stall) 80 // for GPU to finish its job. To avoid waiting (stall), you can call 81 // first glBufferDataARB() with NULL pointer before glMapBufferARB(). 82 // If you do that, the previous data in PBO will be discarded and 83 // glMapBufferARB() returns a new allocated pointer immediately 84 // even if GPU is still working with the previous data. 85 //glBufferData(type, size, null, memtype); 86 void* arrPTR; 87 if (Options.useMapBufferRange) { 88 arrPTR = glMapBufferRange(type,offset,len,GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT ); 89 } else { 90 arrPTR = glMapBuffer(type,GL_WRITE_ONLY); 91 } 92 if (arrPTR !is null) { 93 return (cast(T*)arrPTR)[0..size/T.sizeof]; 94 } else { 95 throw new Exception("cannot map buffer." ); 96 } 97 } 98 99 T[] Map(T)() { 100 Bind(); 101 // map the buffer object into client's memory 102 // Note that glMapBufferARB() causes sync issue. 103 // If GPU is working with this buffer, glMapBufferARB() will wait(stall) 104 // for GPU to finish its job. To avoid waiting (stall), you can call 105 // first glBufferDataARB() with NULL pointer before glMapBufferARB(). 106 // If you do that, the previous data in PBO will be discarded and 107 // glMapBufferARB() returns a new allocated pointer immediately 108 // even if GPU is still working with the previous data. 109 //glBufferData(type, size, null, memtype); 110 void* arrPTR; 111 if (Options.useMapBufferRange) { 112 arrPTR = glMapBufferRange(type,0,size,GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT ); 113 } else { 114 arrPTR = glMapBuffer(type,GL_WRITE_ONLY); 115 } 116 if (arrPTR !is null) { 117 return (cast(T*)arrPTR)[0..size/T.sizeof]; 118 } else { 119 throw new Exception("cannot map buffer." ); 120 } 121 } 122 123 void Unmap() { 124 Bind(); 125 glUnmapBuffer(type); 126 } 127 }