Files
2026-09-26 16:32:40 +03:00

114 lines
1.8 KiB
Go

package texture
import (
"sync"
"aego/gpu"
)
type UploadOptions struct {
Mips bool
Label string
}
type job struct {
data *Data
opt UploadOptions
tex gpu.TextureHandle
err error
ready bool
}
type Pending struct {
j *job
up *Uploader
}
func (p Pending) Ready() (gpu.TextureHandle, bool) {
if p.j == nil {
return gpu.TextureHandle{}, false
}
p.up.mu.Lock()
defer p.up.mu.Unlock()
return p.j.tex, p.j.ready
}
func (p Pending) Err() error {
if p.j == nil {
return nil
}
p.up.mu.Lock()
defer p.up.mu.Unlock()
return p.j.err
}
type Uploader struct {
dev gpu.Device
mu sync.Mutex
queue []*job
pending int
}
func NewUploader(dev gpu.Device) *Uploader {
return &Uploader{dev: dev, queue: make([]*job, 0, 16)}
}
func (u *Uploader) Upload(d *Data, opt UploadOptions) (gpu.TextureHandle, error) {
if err := d.Validate(); err != nil {
return gpu.TextureHandle{}, err
}
if d.Format != gpu.TexR8 {
d.Premultiply()
}
return u.dev.CreateTexture(gpu.TextureDesc{
Width: d.Width,
Height: d.Height,
Format: d.Format,
Mips: opt.Mips,
Data: d.Pixels,
Label: opt.Label,
})
}
func (u *Uploader) Enqueue(d *Data, opt UploadOptions) Pending {
j := &job{data: d, opt: opt}
u.mu.Lock()
u.queue = append(u.queue, j)
u.pending++
u.mu.Unlock()
return Pending{j: j, up: u}
}
func (u *Uploader) Pending() int {
u.mu.Lock()
defer u.mu.Unlock()
return u.pending
}
func (u *Uploader) Drain(maxBytes int) int {
if maxBytes <= 0 {
maxBytes = 1 << 30
}
spent := 0
for spent < maxBytes {
u.mu.Lock()
if len(u.queue) == 0 {
u.mu.Unlock()
return spent
}
j := u.queue[0]
u.queue = u.queue[1:]
u.mu.Unlock()
tex, err := u.Upload(j.data, j.opt)
spent += len(j.data.Pixels)
u.mu.Lock()
j.tex, j.err, j.ready = tex, err, true
j.data = nil
u.pending--
u.mu.Unlock()
}
return spent
}