internal/jsutil: Optimization: Avoid using empty interface{} conversions

This commit is contained in:
Hajime Hoshi 2021-10-30 18:43:46 +09:00
parent a826ecb29b
commit a082db04fd
3 changed files with 52 additions and 81 deletions

View File

@ -242,7 +242,7 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte {
c.bindFramebuffer(f.native) c.bindFramebuffer(f.native)
l := 4 * width * height l := 4 * width * height
p := jsutil.TemporaryUint8Array(l, nil) p := jsutil.TemporaryUint8ArrayFromUint8Slice(l, nil)
gl.readPixels.Invoke(0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE, p) gl.readPixels.Invoke(0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE, p)
return uint8ArrayToSlice(p, l) return uint8ArrayToSlice(p, l)
@ -567,7 +567,7 @@ func (c *context) bindElementArrayBuffer(b buffer) {
func (c *context) arrayBufferSubData(data []float32) { func (c *context) arrayBufferSubData(data []float32) {
gl := c.gl gl := c.gl
l := len(data) * 4 l := len(data) * 4
arr := jsutil.TemporaryUint8Array(l, data) arr := jsutil.TemporaryUint8ArrayFromFloat32Slice(l, data)
if c.usesWebGL2() { if c.usesWebGL2() {
gl.bufferSubData.Invoke(gles.ARRAY_BUFFER, 0, arr, 0, l) gl.bufferSubData.Invoke(gles.ARRAY_BUFFER, 0, arr, 0, l)
} else { } else {
@ -578,7 +578,7 @@ func (c *context) arrayBufferSubData(data []float32) {
func (c *context) elementArrayBufferSubData(data []uint16) { func (c *context) elementArrayBufferSubData(data []uint16) {
gl := c.gl gl := c.gl
l := len(data) * 2 l := len(data) * 2
arr := jsutil.TemporaryUint8Array(l, data) arr := jsutil.TemporaryUint8ArrayFromUint16Slice(l, data)
if c.usesWebGL2() { if c.usesWebGL2() {
gl.bufferSubData.Invoke(gles.ELEMENT_ARRAY_BUFFER, 0, arr, 0, l) gl.bufferSubData.Invoke(gles.ELEMENT_ARRAY_BUFFER, 0, arr, 0, l)
} else { } else {
@ -624,7 +624,7 @@ func (c *context) texSubImage2D(t textureNative, args []*driver.ReplacePixelsArg
c.bindTexture(t) c.bindTexture(t)
gl := c.gl gl := c.gl
for _, a := range args { for _, a := range args {
arr := jsutil.TemporaryUint8Array(len(a.Pixels), a.Pixels) arr := jsutil.TemporaryUint8ArrayFromUint8Slice(len(a.Pixels), a.Pixels)
if c.usesWebGL2() { if c.usesWebGL2() {
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
// GLsizei width, GLsizei height, // GLsizei width, GLsizei height,

View File

@ -92,24 +92,38 @@ func ensureTemporaryArrayBufferSize(byteLength int) {
} }
} }
// TemporaryUint8Array returns a Uint8Array whose length is at least minLength. // TemporaryUint8ArrayFromUint8Slice returns a Uint8Array whose length is at least minLength from a uint8 slice.
// Be careful that the length can exceed the given minLength. // Be careful that the length can exceed the given minLength.
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization. // data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
func TemporaryUint8Array(minLength int, data interface{}) js.Value { func TemporaryUint8ArrayFromUint8Slice(minLength int, data []uint8) js.Value {
ensureTemporaryArrayBufferSize(minLength) ensureTemporaryArrayBufferSize(minLength)
if data != nil { copyUint8SliceToTemporaryArrayBuffer(data)
copySliceToTemporaryArrayBuffer(data) return temporaryUint8Array
} }
// TemporaryUint8ArrayFromUint16Slice returns a Uint8Array whose length is at least minLength from a uint16 slice.
// Be careful that the length can exceed the given minLength.
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
func TemporaryUint8ArrayFromUint16Slice(minLength int, data []uint16) js.Value {
ensureTemporaryArrayBufferSize(minLength * 2)
copyUint16SliceToTemporaryArrayBuffer(data)
return temporaryUint8Array
}
// TemporaryUint8ArrayFromFloat32Slice returns a Uint8Array whose length is at least minLength from a float32 slice.
// Be careful that the length can exceed the given minLength.
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
func TemporaryUint8ArrayFromFloat32Slice(minLength int, data []float32) js.Value {
ensureTemporaryArrayBufferSize(minLength * 4)
copyFloat32SliceToTemporaryArrayBuffer(data)
return temporaryUint8Array return temporaryUint8Array
} }
// TemporaryFloat32Array returns a Float32Array whose length is at least minLength. // TemporaryFloat32Array returns a Float32Array whose length is at least minLength.
// Be careful that the length can exceed the given minLength. // Be careful that the length can exceed the given minLength.
// data must be a slice of a numeric type for initialization, or nil if you don't need initialization. // data must be a slice of a numeric type for initialization, or nil if you don't need initialization.
func TemporaryFloat32Array(minLength int, data interface{}) js.Value { func TemporaryFloat32Array(minLength int, data []float32) js.Value {
ensureTemporaryArrayBufferSize(minLength * 4) ensureTemporaryArrayBufferSize(minLength * 4)
if data != nil { copyFloat32SliceToTemporaryArrayBuffer(data)
copySliceToTemporaryArrayBuffer(data)
}
return temporaryFloat32Array return temporaryFloat32Array
} }

View File

@ -15,82 +15,39 @@
package jsutil package jsutil
import ( import (
"fmt"
"reflect" "reflect"
"runtime" "runtime"
"syscall/js" "syscall/js"
"unsafe" "unsafe"
) )
func sliceToByteSlice(s interface{}) (bs []byte) { func copyUint8SliceToTemporaryArrayBuffer(src []uint8) {
switch s := s.(type) { if len(src) == 0 {
case []int8:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []int16:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 2
h.Cap *= 2
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []int32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []int64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []uint8:
return s
case []uint16:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 2
h.Cap *= 2
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []uint32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []uint64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []float32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
case []float64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
bs = *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(s)
default:
panic(fmt.Sprintf("jsutil: unexpected value at sliceToBytesSlice: %T", s))
}
return return
}
js.CopyBytesToJS(temporaryUint8Array, src)
} }
func copySliceToTemporaryArrayBuffer(src interface{}) { func copyUint16SliceToTemporaryArrayBuffer(src []uint16) {
switch s := src.(type) { if len(src) == 0 {
case []uint8: return
js.CopyBytesToJS(temporaryUint8Array, s)
case []int8, []int16, []int32, []uint16, []uint32, []float32, []float64:
js.CopyBytesToJS(temporaryUint8Array, sliceToByteSlice(s))
default:
panic(fmt.Sprintf("jsutil: unexpected value at CopySliceToJS: %T", s))
} }
h := (*reflect.SliceHeader)(unsafe.Pointer(&src))
h.Len *= 2
h.Cap *= 2
bs := *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(src)
js.CopyBytesToJS(temporaryUint8Array, bs)
}
func copyFloat32SliceToTemporaryArrayBuffer(src []float32) {
if len(src) == 0 {
return
}
h := (*reflect.SliceHeader)(unsafe.Pointer(&src))
h.Len *= 4
h.Cap *= 4
bs := *(*[]byte)(unsafe.Pointer(h))
runtime.KeepAlive(src)
js.CopyBytesToJS(temporaryUint8Array, bs)
} }