I’m generating some textures that i want to stuff into bpy.data.images
, however i am running into severe perf issues setting the actual content.
I’ve narrowed it down to setting image.pixels
being the largest time hog, i did some googling and found that setting img.pixels[:]
would be faster, and indeed it is, but it’s still far far too slow
texture size | pixels = data | pixels[:] = data | pixels=data.tolist | pixels[:]=data.tolist |
---|---|---|---|---|
512px | 0.101513s | 0.069509s | 0.063008s | 0.041005s |
1024px | 0.406052s | 0.280535s | 0.23653s | 0.168522s |
2048px | 1.560198s | 1.159647s | 0.94512s | 0.656084s |
4096px | 6.460321s | 4.418561s | 3.999507s | 2.809357s |
Repro case :
import bpy
import numpy as np
from datetime import datetime
def benchmark(size):
img = bpy.data.images.get("output")
if (img == None):
img = bpy.data.images.new("output", width=size, height=size, alpha=False, float_buffer=True)
if (size != img.generated_width):
img.generated_width = size
if (size != img.generated_height):
img.generated_height = size
pixel_data = np.ones(size*size*4)
t1 = datetime.now()
t0 = datetime.now()
img.pixels = pixel_data
t1 = datetime.now()
meth1 = (t1-t0).total_seconds()
t0 = datetime.now()
img.pixels[:] = pixel_data
t1 = datetime.now()
meth2 = (t1-t0).total_seconds()
t0 = datetime.now()
img.pixels = pixel_data.tolist()
t1 = datetime.now()
meth3 = (t1-t0).total_seconds()
t0 = datetime.now()
img.pixels[:] = pixel_data.tolist()
t1 = datetime.now()
meth4 = (t1-t0).total_seconds()
print("|%spx|%ss|%ss|%ss|%ss|" % ( size , meth1, meth2,meth3,meth4))
benchmark(512)
benchmark(1024)
benchmark(2048)
benchmark(4096)
Any ideas here? I have found some previous work in this area but that seem to be dealing with the reading part, also i don’t think that ever went anywhere.
edit1:
Updated the benchmark code to include .tolist() as @kaio suggested