mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
graphicsdriver/opengl: Experimental PBO implementation
This change is an experimental implementation to use Pixel Buffer Objects. This reduces calls of glTexSubImage2D. This works only on desktops. Unfortunately WebGL does not have this features. Mobiles can have PBO as of OpenGL ES 3. Updates #976
This commit is contained in:
parent
16b3a5c296
commit
acc933b7c3
@ -22,6 +22,7 @@ package opengl
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/driver"
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl/gl"
|
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl/gl"
|
||||||
@ -509,3 +510,42 @@ func (c *context) flush() {
|
|||||||
func (c *context) needsRestoring() bool {
|
func (c *context) needsRestoring() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) newPixelBufferObject(width, height int) buffer {
|
||||||
|
var bf buffer
|
||||||
|
_ = c.t.Call(func() error {
|
||||||
|
var b uint32
|
||||||
|
gl.GenBuffers(1, &b)
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, b)
|
||||||
|
gl.BufferData(gl.PIXEL_UNPACK_BUFFER, 4*width*height, nil, gl.STREAM_DRAW)
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0)
|
||||||
|
bf = buffer(b)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return bf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) mapPixelBuffer(buffer buffer) unsafe.Pointer {
|
||||||
|
var ptr unsafe.Pointer
|
||||||
|
_ = c.t.Call(func() error {
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, uint32(buffer))
|
||||||
|
ptr = gl.MapBuffer(gl.PIXEL_UNPACK_BUFFER, gl.WRITE_ONLY)
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) unmapPixelBuffer(buffer buffer, t textureNative, width, height int) {
|
||||||
|
_ = c.t.Call(func() error {
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, uint32(buffer))
|
||||||
|
gl.UnmapBuffer(gl.PIXEL_UNPACK_BUFFER)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.bindTexture(t)
|
||||||
|
_ = c.t.Call(func() error {
|
||||||
|
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
|
||||||
|
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -470,3 +470,7 @@ func (c *context) flush() {
|
|||||||
func (c *context) needsRestoring() bool {
|
func (c *context) needsRestoring() bool {
|
||||||
return !web.IsMobileBrowser()
|
return !web.IsMobileBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) canUsePBO() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@ const (
|
|||||||
ARRAY_BUFFER = 0x8892
|
ARRAY_BUFFER = 0x8892
|
||||||
ELEMENT_ARRAY_BUFFER = 0x8893
|
ELEMENT_ARRAY_BUFFER = 0x8893
|
||||||
DYNAMIC_DRAW = 0x88E8
|
DYNAMIC_DRAW = 0x88E8
|
||||||
|
STREAM_DRAW = 0x88E0
|
||||||
|
PIXEL_UNPACK_BUFFER = 0x88EC
|
||||||
SHORT = 0x1402
|
SHORT = 0x1402
|
||||||
FLOAT = 0x1406
|
FLOAT = 0x1406
|
||||||
|
|
||||||
@ -56,6 +58,7 @@ const (
|
|||||||
UNSIGNED_BYTE = 0x1401
|
UNSIGNED_BYTE = 0x1401
|
||||||
UNSIGNED_SHORT = 0x1403
|
UNSIGNED_SHORT = 0x1403
|
||||||
VERTEX_SHADER = 0x8B31
|
VERTEX_SHADER = 0x8B31
|
||||||
|
WRITE_ONLY = 0x88B9
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init initializes the OpenGL bindings by loading the function pointers (for
|
// Init initializes the OpenGL bindings by loading the function pointers (for
|
||||||
|
@ -144,6 +144,7 @@ package gl
|
|||||||
// typedef GLboolean (APIENTRYP GPISPROGRAM)(GLuint program);
|
// typedef GLboolean (APIENTRYP GPISPROGRAM)(GLuint program);
|
||||||
// typedef GLboolean (APIENTRYP GPISTEXTURE)(GLuint texture);
|
// typedef GLboolean (APIENTRYP GPISTEXTURE)(GLuint texture);
|
||||||
// typedef void (APIENTRYP GPLINKPROGRAM)(GLuint program);
|
// typedef void (APIENTRYP GPLINKPROGRAM)(GLuint program);
|
||||||
|
// typedef void * (APIENTRYP GPMAPBUFFER)(GLenum target, GLenum access);
|
||||||
// typedef void (APIENTRYP GPPIXELSTOREI)(GLenum pname, GLint param);
|
// typedef void (APIENTRYP GPPIXELSTOREI)(GLenum pname, GLint param);
|
||||||
// typedef void (APIENTRYP GPREADPIXELS)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);
|
// typedef void (APIENTRYP GPREADPIXELS)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);
|
||||||
// typedef void (APIENTRYP GPSHADERSOURCE)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
|
// typedef void (APIENTRYP GPSHADERSOURCE)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
|
||||||
@ -155,6 +156,7 @@ package gl
|
|||||||
// typedef void (APIENTRYP GPUNIFORM2FV)(GLint location, GLsizei count, const GLfloat * value);
|
// typedef void (APIENTRYP GPUNIFORM2FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||||
// typedef void (APIENTRYP GPUNIFORM4FV)(GLint location, GLsizei count, const GLfloat * value);
|
// typedef void (APIENTRYP GPUNIFORM4FV)(GLint location, GLsizei count, const GLfloat * value);
|
||||||
// typedef void (APIENTRYP GPUNIFORMMATRIX4FV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
// typedef void (APIENTRYP GPUNIFORMMATRIX4FV)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
||||||
|
// typedef GLboolean (APIENTRYP GPUNMAPBUFFER)(GLenum target);
|
||||||
// typedef void (APIENTRYP GPUSEPROGRAM)(GLuint program);
|
// typedef void (APIENTRYP GPUSEPROGRAM)(GLuint program);
|
||||||
// typedef void (APIENTRYP GPVERTEXATTRIBPOINTER)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const uintptr_t pointer);
|
// typedef void (APIENTRYP GPVERTEXATTRIBPOINTER)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const uintptr_t pointer);
|
||||||
// typedef void (APIENTRYP GPVIEWPORT)(GLint x, GLint y, GLsizei width, GLsizei height);
|
// typedef void (APIENTRYP GPVIEWPORT)(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
@ -303,6 +305,9 @@ package gl
|
|||||||
// static void glowLinkProgram(GPLINKPROGRAM fnptr, GLuint program) {
|
// static void glowLinkProgram(GPLINKPROGRAM fnptr, GLuint program) {
|
||||||
// (*fnptr)(program);
|
// (*fnptr)(program);
|
||||||
// }
|
// }
|
||||||
|
// static void * glowMapBuffer(GPMAPBUFFER fnptr, GLenum target, GLenum access) {
|
||||||
|
// return (*fnptr)(target, access);
|
||||||
|
// }
|
||||||
// static void glowPixelStorei(GPPIXELSTOREI fnptr, GLenum pname, GLint param) {
|
// static void glowPixelStorei(GPPIXELSTOREI fnptr, GLenum pname, GLint param) {
|
||||||
// (*fnptr)(pname, param);
|
// (*fnptr)(pname, param);
|
||||||
// }
|
// }
|
||||||
@ -336,6 +341,9 @@ package gl
|
|||||||
// static void glowUniformMatrix4fv(GPUNIFORMMATRIX4FV fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) {
|
// static void glowUniformMatrix4fv(GPUNIFORMMATRIX4FV fnptr, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) {
|
||||||
// (*fnptr)(location, count, transpose, value);
|
// (*fnptr)(location, count, transpose, value);
|
||||||
// }
|
// }
|
||||||
|
// static GLboolean glowUnmapBuffer(GPUNMAPBUFFER fnptr, GLenum target) {
|
||||||
|
// return (*fnptr)(target);
|
||||||
|
// }
|
||||||
// static void glowUseProgram(GPUSEPROGRAM fnptr, GLuint program) {
|
// static void glowUseProgram(GPUSEPROGRAM fnptr, GLuint program) {
|
||||||
// (*fnptr)(program);
|
// (*fnptr)(program);
|
||||||
// }
|
// }
|
||||||
@ -401,6 +409,7 @@ var (
|
|||||||
gpIsProgram C.GPISPROGRAM
|
gpIsProgram C.GPISPROGRAM
|
||||||
gpIsTexture C.GPISTEXTURE
|
gpIsTexture C.GPISTEXTURE
|
||||||
gpLinkProgram C.GPLINKPROGRAM
|
gpLinkProgram C.GPLINKPROGRAM
|
||||||
|
gpMapBuffer C.GPMAPBUFFER
|
||||||
gpPixelStorei C.GPPIXELSTOREI
|
gpPixelStorei C.GPPIXELSTOREI
|
||||||
gpReadPixels C.GPREADPIXELS
|
gpReadPixels C.GPREADPIXELS
|
||||||
gpShaderSource C.GPSHADERSOURCE
|
gpShaderSource C.GPSHADERSOURCE
|
||||||
@ -412,6 +421,7 @@ var (
|
|||||||
gpUniform2fv C.GPUNIFORM2FV
|
gpUniform2fv C.GPUNIFORM2FV
|
||||||
gpUniform4fv C.GPUNIFORM4FV
|
gpUniform4fv C.GPUNIFORM4FV
|
||||||
gpUniformMatrix4fv C.GPUNIFORMMATRIX4FV
|
gpUniformMatrix4fv C.GPUNIFORMMATRIX4FV
|
||||||
|
gpUnmapBuffer C.GPUNMAPBUFFER
|
||||||
gpUseProgram C.GPUSEPROGRAM
|
gpUseProgram C.GPUSEPROGRAM
|
||||||
gpVertexAttribPointer C.GPVERTEXATTRIBPOINTER
|
gpVertexAttribPointer C.GPVERTEXATTRIBPOINTER
|
||||||
gpViewport C.GPVIEWPORT
|
gpViewport C.GPVIEWPORT
|
||||||
@ -616,6 +626,11 @@ func LinkProgram(program uint32) {
|
|||||||
C.glowLinkProgram(gpLinkProgram, (C.GLuint)(program))
|
C.glowLinkProgram(gpLinkProgram, (C.GLuint)(program))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MapBuffer(target uint32, access uint32) unsafe.Pointer {
|
||||||
|
ret := C.glowMapBuffer(gpMapBuffer, (C.GLenum)(target), (C.GLenum)(access))
|
||||||
|
return (unsafe.Pointer)(ret)
|
||||||
|
}
|
||||||
|
|
||||||
func PixelStorei(pname uint32, param int32) {
|
func PixelStorei(pname uint32, param int32) {
|
||||||
C.glowPixelStorei(gpPixelStorei, (C.GLenum)(pname), (C.GLint)(param))
|
C.glowPixelStorei(gpPixelStorei, (C.GLenum)(pname), (C.GLint)(param))
|
||||||
}
|
}
|
||||||
@ -660,6 +675,11 @@ func UniformMatrix4fv(location int32, count int32, transpose bool, value *float3
|
|||||||
C.glowUniformMatrix4fv(gpUniformMatrix4fv, (C.GLint)(location), (C.GLsizei)(count), (C.GLboolean)(boolToInt(transpose)), (*C.GLfloat)(unsafe.Pointer(value)))
|
C.glowUniformMatrix4fv(gpUniformMatrix4fv, (C.GLint)(location), (C.GLsizei)(count), (C.GLboolean)(boolToInt(transpose)), (*C.GLfloat)(unsafe.Pointer(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnmapBuffer(target uint32) bool {
|
||||||
|
ret := C.glowUnmapBuffer(gpUnmapBuffer, (C.GLenum)(target))
|
||||||
|
return ret == TRUE
|
||||||
|
}
|
||||||
|
|
||||||
func UseProgram(program uint32) {
|
func UseProgram(program uint32) {
|
||||||
C.glowUseProgram(gpUseProgram, (C.GLuint)(program))
|
C.glowUseProgram(gpUseProgram, (C.GLuint)(program))
|
||||||
}
|
}
|
||||||
@ -813,6 +833,10 @@ func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error {
|
|||||||
if gpLinkProgram == nil {
|
if gpLinkProgram == nil {
|
||||||
return errors.New("glLinkProgram")
|
return errors.New("glLinkProgram")
|
||||||
}
|
}
|
||||||
|
gpMapBuffer = (C.GPMAPBUFFER)(getProcAddr("glMapBuffer"))
|
||||||
|
if gpMapBuffer == nil {
|
||||||
|
return errors.New("glMapBuffer")
|
||||||
|
}
|
||||||
gpPixelStorei = (C.GPPIXELSTOREI)(getProcAddr("glPixelStorei"))
|
gpPixelStorei = (C.GPPIXELSTOREI)(getProcAddr("glPixelStorei"))
|
||||||
if gpPixelStorei == nil {
|
if gpPixelStorei == nil {
|
||||||
return errors.New("glPixelStorei")
|
return errors.New("glPixelStorei")
|
||||||
@ -857,6 +881,10 @@ func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error {
|
|||||||
if gpUniformMatrix4fv == nil {
|
if gpUniformMatrix4fv == nil {
|
||||||
return errors.New("glUniformMatrix4fv")
|
return errors.New("glUniformMatrix4fv")
|
||||||
}
|
}
|
||||||
|
gpUnmapBuffer = (C.GPUNMAPBUFFER)(getProcAddr("glUnmapBuffer"))
|
||||||
|
if gpUnmapBuffer == nil {
|
||||||
|
return errors.New("glUnmapBuffer")
|
||||||
|
}
|
||||||
gpUseProgram = (C.GPUSEPROGRAM)(getProcAddr("glUseProgram"))
|
gpUseProgram = (C.GPUSEPROGRAM)(getProcAddr("glUseProgram"))
|
||||||
if gpUseProgram == nil {
|
if gpUseProgram == nil {
|
||||||
return errors.New("glUseProgram")
|
return errors.New("glUseProgram")
|
||||||
|
@ -58,6 +58,7 @@ var (
|
|||||||
gpIsProgram uintptr
|
gpIsProgram uintptr
|
||||||
gpIsTexture uintptr
|
gpIsTexture uintptr
|
||||||
gpLinkProgram uintptr
|
gpLinkProgram uintptr
|
||||||
|
gpMapBuffer uintptr
|
||||||
gpPixelStorei uintptr
|
gpPixelStorei uintptr
|
||||||
gpReadPixels uintptr
|
gpReadPixels uintptr
|
||||||
gpShaderSource uintptr
|
gpShaderSource uintptr
|
||||||
@ -69,6 +70,7 @@ var (
|
|||||||
gpUniform2fv uintptr
|
gpUniform2fv uintptr
|
||||||
gpUniform4fv uintptr
|
gpUniform4fv uintptr
|
||||||
gpUniformMatrix4fv uintptr
|
gpUniformMatrix4fv uintptr
|
||||||
|
gpUnmapBuffer uintptr
|
||||||
gpUseProgram uintptr
|
gpUseProgram uintptr
|
||||||
gpVertexAttribPointer uintptr
|
gpVertexAttribPointer uintptr
|
||||||
gpViewport uintptr
|
gpViewport uintptr
|
||||||
@ -269,6 +271,11 @@ func IsTexture(texture uint32) bool {
|
|||||||
return ret != 0
|
return ret != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MapBuffer(target uint32, access uint32) unsafe.Pointer {
|
||||||
|
ret, _, _ := syscall.Syscall(gpMapBuffer, 2, uintptr(target), uintptr(access), 0)
|
||||||
|
return unsafe.Pointer(ret)
|
||||||
|
}
|
||||||
|
|
||||||
func LinkProgram(program uint32) {
|
func LinkProgram(program uint32) {
|
||||||
syscall.Syscall(gpLinkProgram, 1, uintptr(program), 0, 0)
|
syscall.Syscall(gpLinkProgram, 1, uintptr(program), 0, 0)
|
||||||
}
|
}
|
||||||
@ -317,6 +324,11 @@ func UniformMatrix4fv(location int32, count int32, transpose bool, value *float3
|
|||||||
syscall.Syscall6(gpUniformMatrix4fv, 4, uintptr(location), uintptr(count), boolToUintptr(transpose), uintptr(unsafe.Pointer(value)), 0, 0)
|
syscall.Syscall6(gpUniformMatrix4fv, 4, uintptr(location), uintptr(count), boolToUintptr(transpose), uintptr(unsafe.Pointer(value)), 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnmapBuffer(target uint32) bool {
|
||||||
|
ret, _, _ := syscall.Syscall(gpUnmapBuffer, 1, uintptr(target), 0, 0)
|
||||||
|
return ret != 0
|
||||||
|
}
|
||||||
|
|
||||||
func UseProgram(program uint32) {
|
func UseProgram(program uint32) {
|
||||||
syscall.Syscall(gpUseProgram, 1, uintptr(program), 0, 0)
|
syscall.Syscall(gpUseProgram, 1, uintptr(program), 0, 0)
|
||||||
}
|
}
|
||||||
@ -466,6 +478,10 @@ func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error {
|
|||||||
if gpIsTexture == 0 {
|
if gpIsTexture == 0 {
|
||||||
return errors.New("glIsTexture")
|
return errors.New("glIsTexture")
|
||||||
}
|
}
|
||||||
|
gpMapBuffer = getProcAddr("glMapBuffer")
|
||||||
|
if gpMapBuffer == 0 {
|
||||||
|
return errors.New("glMapBuffer")
|
||||||
|
}
|
||||||
gpLinkProgram = getProcAddr("glLinkProgram")
|
gpLinkProgram = getProcAddr("glLinkProgram")
|
||||||
if gpLinkProgram == 0 {
|
if gpLinkProgram == 0 {
|
||||||
return errors.New("glLinkProgram")
|
return errors.New("glLinkProgram")
|
||||||
@ -514,6 +530,10 @@ func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error {
|
|||||||
if gpUniformMatrix4fv == 0 {
|
if gpUniformMatrix4fv == 0 {
|
||||||
return errors.New("glUniformMatrix4fv")
|
return errors.New("glUniformMatrix4fv")
|
||||||
}
|
}
|
||||||
|
gpUnmapBuffer = getProcAddr("glUnmapBuffer")
|
||||||
|
if gpUnmapBuffer == 0 {
|
||||||
|
return errors.New("glUnmapBuffer")
|
||||||
|
}
|
||||||
gpUseProgram = getProcAddr("glUseProgram")
|
gpUseProgram = getProcAddr("glUseProgram")
|
||||||
if gpUseProgram == 0 {
|
if gpUseProgram == 0 {
|
||||||
return errors.New("glUseProgram")
|
return errors.New("glUseProgram")
|
||||||
|
@ -22,6 +22,7 @@ type Image struct {
|
|||||||
driver *Driver
|
driver *Driver
|
||||||
textureNative textureNative
|
textureNative textureNative
|
||||||
framebuffer *framebuffer
|
framebuffer *framebuffer
|
||||||
|
pbo buffer
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
screen bool
|
screen bool
|
||||||
@ -32,6 +33,10 @@ func (i *Image) IsInvalidated() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Dispose() {
|
func (i *Image) Dispose() {
|
||||||
|
thePBOState.ensurePBOUnmapped()
|
||||||
|
if i.pbo != *new(buffer) {
|
||||||
|
i.driver.context.deleteBuffer(i.pbo)
|
||||||
|
}
|
||||||
if i.framebuffer != nil {
|
if i.framebuffer != nil {
|
||||||
i.framebuffer.delete(&i.driver.context)
|
i.framebuffer.delete(&i.driver.context)
|
||||||
}
|
}
|
||||||
@ -53,6 +58,7 @@ func (i *Image) setViewport() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Pixels() ([]byte, error) {
|
func (i *Image) Pixels() ([]byte, error) {
|
||||||
|
thePBOState.ensurePBOUnmapped()
|
||||||
if err := i.ensureFramebuffer(); err != nil {
|
if err := i.ensureFramebuffer(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -96,7 +102,13 @@ func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
|
|||||||
i.driver.context.flush()
|
i.driver.context.flush()
|
||||||
}
|
}
|
||||||
i.driver.drawCalled = false
|
i.driver.drawCalled = false
|
||||||
i.driver.context.texSubImage2D(i.textureNative, p, x, y, width, height)
|
|
||||||
|
if canUsePBO {
|
||||||
|
thePBOState.mapPBOIfNecessary(i)
|
||||||
|
thePBOState.draw(p, x, y, width, height)
|
||||||
|
} else {
|
||||||
|
i.driver.context.texSubImage2D(i.textureNative, p, x, y, width, height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) SetAsSource() {
|
func (i *Image) SetAsSource() {
|
||||||
|
87
internal/graphicsdriver/opengl/pbo_desktop.go
Normal file
87
internal/graphicsdriver/opengl/pbo_desktop.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2019 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build darwin freebsd linux windows
|
||||||
|
// +build !js
|
||||||
|
// +build !android
|
||||||
|
// +build !ios
|
||||||
|
|
||||||
|
package opengl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||||
|
)
|
||||||
|
|
||||||
|
const canUsePBO = true
|
||||||
|
|
||||||
|
type pboState struct {
|
||||||
|
image *Image
|
||||||
|
mappedPBO unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
var thePBOState pboState
|
||||||
|
|
||||||
|
func (s *pboState) mapPBOIfNecessary(img *Image) {
|
||||||
|
if s.image == img {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ensurePBOUnmapped()
|
||||||
|
|
||||||
|
if img.pbo == *new(buffer) {
|
||||||
|
w, h := graphics.InternalImageSize(img.width), graphics.InternalImageSize(img.height)
|
||||||
|
img.pbo = img.driver.context.newPixelBufferObject(w, h)
|
||||||
|
}
|
||||||
|
s.image = img
|
||||||
|
s.mappedPBO = img.driver.context.mapPixelBuffer(img.pbo)
|
||||||
|
|
||||||
|
if s.mappedPBO == nil {
|
||||||
|
panic("opengl: mapPixelBuffer failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *pboState) draw(pix []byte, x, y, width, height int) {
|
||||||
|
w, h := graphics.InternalImageSize(s.image.width), graphics.InternalImageSize(s.image.height)
|
||||||
|
|
||||||
|
var mapped []byte
|
||||||
|
sh := (*reflect.SliceHeader)(unsafe.Pointer(&mapped))
|
||||||
|
sh.Data = uintptr(s.mappedPBO)
|
||||||
|
sh.Len = 4 * w * h
|
||||||
|
sh.Cap = 4 * w * h
|
||||||
|
|
||||||
|
stride := 4 * w
|
||||||
|
offset := 4 * (y*w + x)
|
||||||
|
for j := 0; j < height; j++ {
|
||||||
|
copy(mapped[offset+stride*j:offset+stride*j+4*width], pix[4*width*j:4*width*(j+1)])
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.KeepAlive(mapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *pboState) ensurePBOUnmapped() {
|
||||||
|
if s.mappedPBO == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i := s.image
|
||||||
|
w, h := graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||||
|
i.driver.context.unmapPixelBuffer(i.pbo, i.textureNative, w, h)
|
||||||
|
|
||||||
|
s.image = nil
|
||||||
|
s.mappedPBO = nil
|
||||||
|
}
|
35
internal/graphicsdriver/opengl/pbo_notdesktop.go
Normal file
35
internal/graphicsdriver/opengl/pbo_notdesktop.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2019 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build js android ios
|
||||||
|
|
||||||
|
package opengl
|
||||||
|
|
||||||
|
const canUsePBO = false
|
||||||
|
|
||||||
|
type pboState struct{}
|
||||||
|
|
||||||
|
var thePBOState pboState
|
||||||
|
|
||||||
|
func (s *pboState) mapPBOIfNecessary(img *Image) {
|
||||||
|
panic("opengl: PBO is not available in this environment")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *pboState) draw(pix []byte, x, y, width, height int) {
|
||||||
|
panic("opengl: PBO is not available in this environment")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *pboState) ensurePBOUnmapped() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
@ -265,6 +265,8 @@ func (d *Driver) useProgram(mode driver.CompositeMode, colorM *affine.ColorM, fi
|
|||||||
panic("source image is not set")
|
panic("source image is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thePBOState.ensurePBOUnmapped()
|
||||||
|
|
||||||
if err := destination.setViewport(); err != nil {
|
if err := destination.setViewport(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user