def _activate(self): """ Activate texture on GPU """ log.debug("GPU: Activate texture") gl.glBindTexture(self.target, self._handle) if self._need_setup: self._setup()
def _update(self): """ Update texture on GPU """ if self.pending_data: log.debug("GPU: Updating texture") start, stop = self.pending_data offset, nbytes = start, stop - start itemsize = self.strides[1] offset /= itemsize nbytes /= itemsize nbytes += offset % self.width offset -= offset % self.width nbytes += (self.width - ((offset + nbytes) % self.width)) % self.width x = 0 y = offset // self.width width = self.width height = nbytes // self.width gl.glBindTexture(self._target, self.handle) gl.glTexSubImage2D(self.target, 0, x, y, width, height, self._cpu_format, self.gtype, self) gl.glBindTexture(self._target, self.handle) self._pending_data = None self._need_update = False
def _update(self): """ Update texture on GPU """ if self.pending_data: log.debug("GPU: Updating texture") start, stop = self.pending_data offset, nbytes = start, stop-start itemsize = self.strides[1] offset /= itemsize nbytes /= itemsize nbytes += offset % self.width offset -= offset % self.width nbytes += (self.width - ((offset + nbytes) % self.width)) % self.width x = 0 y = offset // self.width width = self.width height = nbytes // self.width gl.glBindTexture(self._target, self.handle) gl.glTexSubImage2D(self.target, 0, x, y, width, height, self._cpu_format, self.gtype, self) gl.glBindTexture(self._target, self.handle) self._pending_data = None self._need_update = False
def _create(self): Texture._create(self) log.debug("GPU: Resizing texture(%s)"% (self.width)) gl.glBindTexture(self.target, self._handle) gl.glTexImage1D(self.target, 0, self.format, self.width, 0, self.format, self.gtype, None)
def _update(self): """ Update texture on GPU """ if self.pending_data: log.debug("GPU: Updating texture") # offset, nbytes = self.pending_data # itemsize = self.strides[1] # offset /= itemsize # nbytes /= itemsize # nbytes += offset % self.width # offset -= offset % self.width # nbytes += (self.width - ((offset + nbytes) % self.width)) % self.width x = 0 y = 0 z = 0 width = self.width height = self.height depth = self.depth gl.glBindTexture(self._target, self.handle) gl.glTexSubImage3D(self.target, 0, x, y, z, width, height, depth, self._cpu_format, self.gtype, self) gl.glBindTexture(self._target, self.handle) self._pending_data = None self._need_update = False
def _create(self): """ Create texture on GPU """ Texture._create(self) log.debug("GPU: Resizing texture(%sx%s)"% (self.width,self.height)) gl.glBindTexture(self.target, self._handle) gl.glTexImage2D(self.target, 0, self.format, self.width, self.height, 0, self.format, self.gtype, None)
def _setup(self): """ Setup texture on GPU """ Texture._setup(self) gl.glBindTexture(self.target, self._handle) gl.glTexImage2D(self.target, 0, self._gpu_format, self.width, self.height, 0, self._cpu_format, self.gtype, None) self._need_setup = False
def _activate(self): """ Activate texture on GPU """ log.debug("GPU: Activate texture cube") gl.glEnable(gl.GL_TEXTURE_CUBE_MAP) gl.glBindTexture(self.target, self._handle) if self._need_setup: self._setup()
def _transfer_frame_pbo(self): # generate PBO's if self._video_thread.has_video_loaded and (self._pbo_shape != self._video_thread.frame.shape): if self._pbos is not None: gl.glDeleteBuffers(PBO_COUNT, self._pbos) self._pbo_shape = self._video_thread.frame.shape self._pbos = gl.glGenBuffers(PBO_COUNT) h, w, b = self._pbo_shape num_bytes = h*w*b for pbo in self._pbos: gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo) gl.glBufferData(gl.GL_PIXEL_UNPACK_BUFFER, num_bytes, None, gl.GL_STREAM_DRAW) gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0) # generate/update OpenGL texture if (self._frame is None or self._frame.shape != self._pbo_shape) and self._pbo_shape is not None: self._frame = np.zeros(self._pbo_shape, dtype=np.uint8).view(gloo.Texture2D) self._frame.activate() self._frame.deactivate() # do the transfer of pixel data from cpu to gpu using PBO's # inspired by this: https://gist.github.com/roxlu/4663550 if self._video_thread.has_video_loaded and self._video_thread.frame_changed: self._video_thread.frame_changed = False pbo = self._pbos[self._pbo_index] gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo) t = self._frame._handle h, w, b = self._pbo_shape assert t != None and t != 0 gl.glBindTexture(gl.GL_TEXTURE_2D, t) gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, w, h, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None) h, w, b = self._pbo_shape num_bytes = h*w*b self._pbo_index = (self._pbo_index + 1) % PBO_COUNT pbo = self._pbos[self._pbo_index] gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, pbo) # this might be an alternative, but not so fast as tested so far #gl.glBufferSubData(gl.GL_PIXEL_UNPACK_BUFFER, 0, num_bytes, ctypes.c_void_p(self._video_thread.frame.ctypes.data)) ptr = gl.glMapBuffer(gl.GL_PIXEL_UNPACK_BUFFER, gl.GL_WRITE_ONLY) if ptr != 0: #start = time.time() ctypes.memmove(ctypes.c_voidp(ptr), ctypes.c_void_p(self._video_thread.frame.ctypes.data), num_bytes) #end = time.time() #elapsed = end - start #print("Took %.2fms, %.2fMB/s" % (elapsed * 1000, (num_bytes / 1000000) / elapsed)) gl.glUnmapBuffer(gl.GL_PIXEL_UNPACK_BUFFER) gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0)
def _setup(self): """ Setup texture on GPU """ Texture._setup(self) gl.glEnable(gl.GL_TEXTURE_CUBE_MAP) gl.glBindTexture(self.target, self._handle) targets = [ gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ] for i,target in enumerate(targets): gl.glTexImage2D(target, 0, self._gpu_format, self.width, self.height, 0, self._cpu_format, self.gtype, None) self._need_setup = False
def _set_wrapping(self): """ Setup texture on GPU """ min_filter, mag_filter = self._interpolation wrapping = self._wrapping # not optimal solution perhaps # texture might be not set up yet # but calling _activate() would set wrapping again and so this would lead to recursion gl.glBindTexture(self.target, self._handle) gl.glTexParameterf(self.target, gl.GL_TEXTURE_MIN_FILTER, min_filter) gl.glTexParameterf(self.target, gl.GL_TEXTURE_MAG_FILTER, mag_filter) gl.glTexParameterf(self.target, gl.GL_TEXTURE_WRAP_S, wrapping) gl.glTexParameterf(self.target, gl.GL_TEXTURE_WRAP_T, wrapping) gl.glTexParameterf(self.target, gl.GL_TEXTURE_WRAP_R, gl.GL_CLAMP_TO_EDGE) gl.glBindTexture(self.target, 0)
def _update(self): log.debug("GPU: Updating texture cube") if self.need_update: gl.glEnable(gl.GL_TEXTURE_CUBE_MAP) gl.glBindTexture(self.target, self.handle) targets = [ gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ] for i, target in enumerate(targets): face = self[i] pending = self.pending_data extents = face._extents if pending is None: continue if pending[1] < extents[0]: continue if pending[0] > extents[1]: continue start = max(extents[0], pending[0]) - extents[0] stop = min(extents[1], pending[1]) - extents[0] offset, nbytes = start, stop - start itemsize = face.strides[1] offset /= itemsize nbytes /= itemsize nbytes += offset % self.width offset -= offset % self.width nbytes += (self.width - ((offset + nbytes) % self.width)) % self.width x = 0 y = offset // self.width width = self.width height = nbytes // self.width gl.glTexSubImage2D(target, 0, x, y, width, height, self._cpu_format, self.gtype, face) self._pending_data = None self._need_update = False
def _download_texture(self, texture): # generate PBO's if self._pbos is None or self._pbo_shape != texture.shape: if self._pbos is not None: gl.glDeleteBuffers(2, self._pbos) self._pbo_shape = texture.shape self._pbos = gl.glGenBuffers(2) h, w, b = self._pbo_shape num_bytes = h*w*b for pbo in self._pbos: gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo) gl.glBufferData(gl.GL_PIXEL_PACK_BUFFER, num_bytes, None, gl.GL_STREAM_DRAW) gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0) # do the transfer of pixel data from gpu to cpu using PBO's # inspired by this: https://gist.github.com/roxlu/4663550 h, w, b = self._pbo_shape b -= 1 num_bytes = h*w*b pbo = self._pbos[self._pbo_index] gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo) t = texture._handle assert t != None and t != 0 gl.glBindTexture(gl.GL_TEXTURE_2D, t) gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0)) self._pbo_index = (self._pbo_index + 1) % 2 pbo = self._pbos[self._pbo_index] gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pbo) ptr = gl.glMapBuffer(gl.GL_PIXEL_PACK_BUFFER, gl.GL_READ_ONLY) data = None if ptr != 0: p = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_ubyte * num_bytes)) data = np.frombuffer(p.contents, dtype=np.uint8).copy().reshape((h, w, b)) gl.glUnmapBuffer(gl.GL_PIXEL_PACK_BUFFER) gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0) assert data is not None return data
def _update(self): log.debug("GPU: Updating texture cube") if self.need_update: gl.glEnable(gl.GL_TEXTURE_CUBE_MAP) gl.glBindTexture(self.target, self.handle) targets = [ gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ] for i,target in enumerate(targets): face = self[i] pending = self.pending_data extents = face._extents if pending is None: continue if pending[1] < extents[0]: continue if pending[0] > extents[1]: continue start = max(extents[0], pending[0]) - extents[0] stop = min(extents[1], pending[1]) - extents[0] offset,nbytes = start, stop-start itemsize = face.strides[1] offset /= itemsize nbytes /= itemsize nbytes += offset % self.width offset -= offset % self.width nbytes += (self.width - ((offset + nbytes) % self.width)) % self.width x = 0 y = offset // self.width width = self.width height = nbytes // self.width gl.glTexSubImage2D(target, 0, x, y, width, height, self._cpu_format, self.gtype, face) self._pending_data = None self._need_update = False
def _deactivate(self): """ Deactivate texture on GPU """ log.debug("GPU: Deactivate texture") gl.glBindTexture(self._target, 0)
def render(self, draw_data): # perf: local for faster access io = self.io display_width, display_height = io.display_size fb_width = int(display_width * io.display_fb_scale[0]) fb_height = int(display_height * io.display_fb_scale[1]) if fb_width == 0 or fb_height == 0: return draw_data.scale_clip_rects(*io.display_fb_scale) # backup GL state # todo: provide cleaner version of this backup-restore code last_program = gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM) last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D) last_active_texture = gl.glGetIntegerv(gl.GL_ACTIVE_TEXTURE) last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING) last_element_array_buffer = gl.glGetIntegerv( gl.GL_ELEMENT_ARRAY_BUFFER_BINDING) last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING) last_blend_src = gl.glGetIntegerv(gl.GL_BLEND_SRC) last_blend_dst = gl.glGetIntegerv(gl.GL_BLEND_DST) last_blend_equation_rgb = gl.glGetIntegerv(gl.GL_BLEND_EQUATION_RGB) last_blend_equation_alpha = gl.glGetIntegerv( gl.GL_BLEND_EQUATION_ALPHA) last_viewport = gl.glGetIntegerv(gl.GL_VIEWPORT) last_scissor_box = gl.glGetIntegerv(gl.GL_SCISSOR_BOX) last_enable_blend = gl.glIsEnabled(gl.GL_BLEND) last_enable_cull_face = gl.glIsEnabled(gl.GL_CULL_FACE) last_enable_depth_test = gl.glIsEnabled(gl.GL_DEPTH_TEST) last_enable_scissor_test = gl.glIsEnabled(gl.GL_SCISSOR_TEST) gl.glEnable(gl.GL_BLEND) gl.glBlendEquation(gl.GL_FUNC_ADD) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glDisable(gl.GL_CULL_FACE) gl.glDisable(gl.GL_DEPTH_TEST) gl.glEnable(gl.GL_SCISSOR_TEST) #gl.glActiveTexture(gl.GL_TEXTURE0) gl.glViewport(0, 0, int(fb_width), int(fb_height)) ortho_projection = (ctypes.c_float * 16)(2.0 / display_width, 0.0, 0.0, 0.0, 0.0, 2.0 / -display_height, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0) self.prog["ProjMtx"] = ortho_projection for commands in draw_data.commands_lists: idx_buffer_offset = 0 array_type = c_ubyte * commands.vtx_buffer_size * imgui.VERTEX_SIZE data_carray = array_type.from_address(commands.vtx_buffer_data) if not ( imgui.VERTEX_BUFFER_POS_OFFSET == 0 and \ imgui.VERTEX_BUFFER_UV_OFFSET == 8 and \ imgui.VERTEX_BUFFER_COL_OFFSET == 16 ): log.error( "GlumpyRenderer.render(): imgui vertex buffer layout has changed ! notify the developers ..." ) return #TODO: this is a bit convoluted; Imgui delivers uint8 colors, but glumpy wants float32's dtype = [('Position', np.float32, 2), ('UV', np.float32, 2), ('Color', np.uint8, 4)] vao_content = np.frombuffer(data_carray, dtype=dtype) dtype2 = [('Position', np.float32, 2), ('UV', np.float32, 2), ('Color', np.float32, 4)] vao_content_f = np.zeros(vao_content.shape, dtype=dtype2) for i, val in enumerate(vao_content): vao_content_f[i] = vao_content[i] vao_content_f[i]['Color'] /= 255 v_array = vao_content_f.view(gloo.VertexArray) self.prog.bind(v_array) if imgui.INDEX_SIZE == 1: dtype = np.uint8 if imgui.INDEX_SIZE == 2: dtype = np.uint16 if imgui.INDEX_SIZE == 4: dtype = np.uint32 # gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._elements_handle) # # todo: check this (sizes) # gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, commands.idx_buffer_size * imgui.INDEX_SIZE, ctypes.c_void_p(commands.idx_buffer_data), gl.GL_STREAM_DRAW) array_type = c_ubyte * commands.idx_buffer_size * imgui.INDEX_SIZE data_carray = array_type.from_address(commands.idx_buffer_data) idx_content = np.frombuffer(data_carray, dtype=dtype) for command in commands.commands: # TODO: ImGui Images will not work yet, homogenizing texture id # allocation by imgui/glumpy is likely a larger issue # #accessing command.texture_id crashes the prog # #gl.glBindTexture(gl.GL_TEXTURE_2D, command.texture_id ) x, y, z, w = command.clip_rect gl.glScissor(int(x), int(fb_height - w), int(z - x), int(w - y)) idx_array = idx_content[idx_buffer_offset:( idx_buffer_offset + command.elem_count)].view( gloo.IndexBuffer) self.prog.draw(mode=gl.GL_TRIANGLES, indices=idx_array) idx_buffer_offset += command.elem_count # restore modified GL state gl.glUseProgram(last_program) gl.glActiveTexture(last_active_texture) gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture) gl.glBindVertexArray(last_vertex_array) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer) gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer) gl.glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha) gl.glBlendFunc(last_blend_src, last_blend_dst) if last_enable_blend: gl.glEnable(gl.GL_BLEND) else: gl.glDisable(gl.GL_BLEND) if last_enable_cull_face: gl.glEnable(gl.GL_CULL_FACE) else: gl.glDisable(gl.GL_CULL_FACE) if last_enable_depth_test: gl.glEnable(gl.GL_DEPTH_TEST) else: gl.glDisable(gl.GL_DEPTH_TEST) if last_enable_scissor_test: gl.glEnable(gl.GL_SCISSOR_TEST) else: gl.glDisable(gl.GL_SCISSOR_TEST) gl.glViewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3]) gl.glScissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3]) log.debug("----------------------end---------------------------------")
def get(self): """ Read the texture data back into CPU memory """ host = np.zeros(self.shape, self.dtype) gl.glBindTexture(self.target, self._handle) gl.glGetTexImage(self.target, 0, self.cpu_format, self.gtype, host) return host
def _deactivate(self): """ Deactivate texture on GPU """ log.debug("GPU: Deactivate texture cube") gl.glBindTexture(self._target, 0) gl.glDisable(gl.GL_TEXTURE_CUBE_MAP)