How to correctly replace the buffer of a TextureSample?

Hi!

I am trying to replace the buffer of a TextureSample with this code:

// Previously I loaded a texture into m_current_texsampler_gpu
TextureSampler m_current_texsampler_gpu = loadTexture(m_context, m_obj_path + "/models/ROSA01.ppm", make_float3(1.0f, 1.0f, 1.0f));

[...]

Buffer texture_buffer = m_context->createBuffer(RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_UNSIGNED_BYTE4);
m_current_texsampler_gpu->setBuffer(texture_buffer);
m_context["diff_tex"]->setTextureSampler(m_current_texsampler_gpu);

[...]

// I try copy the texture information into the buffer
TextureSampler t = loadTexture(m_context, m_obj_path + "/models/tv.ppm", make_float3(1.0f, 1.0f, 1.0f));
RTsize tsize;
t->getBuffer()->getSize(tsize);
texture_buffer->setSize(tsize);

uchar4* tb = static_cast<uchar4*>(t->getBuffer()->map());
t->getBuffer()->unmap();

memcpy(texture_buffer->map(), tb, sizeof(uchar4)*tsize);
texture_buffer->unmap();

The result is a grey sphere, without texture…

Bugs first:

1.) You access a mapped buffer pointer after it has been unmapped!
That is illegal and could just crash the app with an access violation.
=> Line 19 belongs to line 23.

2.) Texture buffers cannot be RT_BUFFER_INPUT_OUTPUT. They must be RT_BUFFER_INPUT.

Then I would not recommend to use those OptiX SDK example framework functions for your case.
The loadTexture() creates a complete texture sampler and texture buffer from scratch.
You neither use that, nor does your the code clean up any of the unused resource.

How I would implement this is like this:

  • Create a single buffer to hold the texture data. Maybe start off with a 1x1 white RGBA8 buffer.
  • Then create a single texture sampler and assign that one buffer to it. Rendering with that should result in a white texture.

If that works continue like this:

  • Implement your own function which loads some image from disk.
    The loadTexture() code should contain that inside.
    Don’t put the image data into OptiX buffers at that point, just keep the image data in an abstract host image format.

  • For the texture you want to put into that single texture buffer, load the desired image, then resize the texture buffer to the matching size, map the buffer, copy the image data over from the host, unmap the texture buffer.

Basically take PPMLoader::loadTexture() apart and split it into these two steps (texture sampler creation, texture buffer filling).

Since the texture sampler is not changed and just the buffer data has been updated, that’s all!
The next launch should grab the new data for that texture sampler.

Generally I recommend to get used to the native OptiX API instead of trying to reuse code from the SDK examples which are often using convenience functions for exactly one specific purpose.
If you have another purpose you’re better off to implement a more dedicated function for that which can be simpler and more efficient.

texture_buffer = m_context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_BYTE4, 1, 1);
m_current_texsampler_gpu = m_context->createTextureSampler();	
	m_current_texsampler_gpu->setWrapMode(0, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setWrapMode(1, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setWrapMode(2, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
	m_current_texsampler_gpu->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
	m_current_texsampler_gpu->setMaxAnisotropy(1.0f);
	m_current_texsampler_gpu->setMipLevelCount(1u);
	m_current_texsampler_gpu->setArraySize(1u);

	m_current_texsampler_gpu->setBuffer(texture_buffer);
        m_context["diff_tex"]->setTextureSampler(m_current_texsampler_gpu);

But I dont get a white texture.

What am I doing wrong?

Thanks by your help!!

Are you sure, that you filled texture_buffer by “white pixel”?

char * data = texture_buffer->map();
data[0] = data[1] = data[2] = data[3] = 255;
texture_buffer->unmap();

Use unsigned data!

texture_buffer = m_context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_<b>UNSIGNED_</b>BYTE4, 1, 1);

unsigned char* data = (unsigned char*) texture_buffer->map();
data[0] = data[1] = data[2] = data[3] = 255u;
texture_buffer->unmap();

The code inside the PPMLoader::loadTexture() function shows that correctly:
optix::Buffer buffer = context->createBuffer( RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_BYTE4, 1u, 1u );

Thanks!, that was my problem.

But now the program render a black sphere

texture_buffer = m_context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_BYTE4, 1, 1);
	char* data = static_cast<char*>(texture_buffer->map());
	data[0] = data[1] = data[2] = data[3] = 255;
	texture_buffer->unmap();

	m_current_texsampler_gpu = m_context->createTextureSampler();	
	m_current_texsampler_gpu->setWrapMode(0, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setWrapMode(1, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setWrapMode(2, RT_WRAP_REPEAT);
	m_current_texsampler_gpu->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
	m_current_texsampler_gpu->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
	m_current_texsampler_gpu->setMaxAnisotropy(1.0f);
	m_current_texsampler_gpu->setMipLevelCount(1u);
	m_current_texsampler_gpu->setArraySize(1u);

	m_current_texsampler_gpu->setBuffer(texture_buffer);
        m_context["diff_tex"]->setTextureSampler(m_current_texsampler_gpu);

Seriously, how did you post that message without reading my post which explains exactly what is wrong?!

I’m sorry, in my haste I did not read this line:
optix::Buffer buffer = context->createBuffer( RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_BYTE4, 1u, 1u );

Seriously, I’m sorry.

The code generate correctly a white texture.

Now I will try to load the texture…

Perfect! I correctly loaded the texture with your method.

Thank you very much for your help!