rtBufferSetDevicePointer : problem to update

Hi,

I initialize my buffer like this (p_tab is a cpu buffer):

std::string nameBuffer = "Sh_buffer";
optix::Variable var = m_context->declareVariable(nameBuffer);
optix::Buffer buf;
int d;
cudaGetDevice(&d);
buf = m_context->createBufferForCUDA(RT_BUFFER_INPUT,RT_FORMAT_USER,width,height,depth);
buf->setElementSize(tailleElementaire) ;
T* d_test;
cudaMalloc((void**)&d_test,width*height*depth*tailleElementaire);
cudaMemcpy(d_test,p_tab,width*height*depth*tailleElementaire,cudaMemcpyHostToDevice);
rtBufferSetDevicePointer(buf->get(), d,(CUdeviceptr)d_test);

This works well: the value of the index SH_buffer requested is correct.

I want to change the value of SH_buffer when the camera is moving. I tried several methods:

Method 1

optix::Buffer buf = m_context[nameBuffer]->getBuffer();
T* d_test;
cudaMalloc((void**)&d_test,width*height*depth*tailleElementaire);
float* h_test = (float*)malloc(width*height*depth*tailleElementaire);
for(int i=0 ; i<width*height*depth ; i++)
	h_test[i]=8;
cudaMemcpy(d_test,h_test,width*height*depth*tailleElementaire,cudaMemcpyHostToDevice);
rtBufferSetDevicePointer(buf->get(), 0,(CUdeviceptr)d_test);
m_context[nameBuffer]->set(buf);

Error :

Invalid value (Details: Function "_rtContextLaunch2D" caught exception: Encountered a CUDA error: driver().cuMemcpyPeer( other_devmem->getDevicePtr(), device->getCudaContext()->getCUcontext(), my_devmem->getDevicePtr(), my_device->getCudaContext()->getCUcontext(), numBytes) returned (1): Invalid value, [786493])

Methode 2 (use both rtBufferSetDevicePointer rtBufferGetDevicePointer)

optix::Buffer buf = m_context[nameBuffer]->getBuffer();
T* d_test;
cudaMalloc((void**)&d_test,width*height*depth*tailleElementaire);
rtBufferGetDevicePointer(buf->get(), 0,(void**)&d_test);
float* h_test = (float*)malloc(width*height*depth*tailleElementaire);
for(int i=0 ; i<width*height*depth ; i++)
    h_test[i]=8;
cudaMemcpy(d_test,h_test,width*height*depth*tailleElementaire,cudaMemcpyHostToDevice);
rtBufferSetDevicePointer(buf->get(), 0,(CUdeviceptr)d_test);
m_context[nameBuffer]->set(buf);

No error but no change in the value of SH_buffer with the method 2.

Can you tell me how to change the value of the buffer just before use rtTrace ?

I might be wrong but… I don’t see a binding between your OptiX buffer and your OptiX variable.

OptiX buffers usually work like this:

  1. You create an OptiX buffer and possibly populate it with data (buffer Map and UnMap do map the buffer to the host so you can effectively write to them without allocation problems)

  2. You create an OptiX variable which will later be referenced in your context somewhere to write/read to your buffer (depending on the type of buffer, remember that INPUT means INPUT with respect to the device)

  3. You create a binding between your OptiX buffer (or OptiX object) and your OptiX variable. This ensures that you can use that variable to write/read from your OptiX buffer.

Without point 3), a buffer is quite useless (there are other cases but I’m talking for the most common ones). Since a buffer may be linked to multiple variables, OptiX is not complaining, but in my opinion something is missing

Take a look at rtVariableSetObject in the OptiX API reference or programming guide.

Hi

I get my variable “buf” in this way:
optix :: Buffer buf = m_context [“Sh_buffer”] -> GetBuffer ();

Is this the link you were talking about?
If this is the case, I forgot to copy my code snippet (I eddited my first post)

Nope, a buffer is just a memory area. To be effectively used it must be associated to a variable. You use your variable to write/read to the buffer. Take a look at rtVariableSetObject in the OptiX API reference or programming guide.

Mind that the C++ wrappers use rtVariableSetObject automatically when setting a named variable.

Still I would agree that the connection to the variable is missing in the first code block. (One of the reasons why full source code attachments would be preferred.)

If you did not call m_context[“Sh_buffer”]->setBuffer(buf); or m_context[“Sh_buffer”]->set(buf); at the end, all you have is a buffer variable and a buffer in that first code block but the assignment is missing, so it’s unclear what buffer you get in all the other code blocks doing optix::Buffer buf = m_context[nameBuffer]->getBuffer();

Please also have a look at this thread with respect to the markDirty() handling. That might affect your method 2. https://devtalk.nvidia.com/default/topic/558491

Hi.

Thanks you for your answers

Yes, the connection was missing.
I corrected and tried this :

optix::Variable var = m_context->declareVariable("SH_buffer");
optix::Buffer buf = m_context->createBufferForCUDA(RT_BUFFER_INPUT,RT_FORMAT_USER,width,height,depth);
buf->setElementSize(tailleElementaire) ;
T* d_test;
cudaMalloc((void**)&d_test,width*height*depth*tailleElementaire);
cudaMemcpy(d_test,p_tab1,width*height*depth*tailleElementaire,cudaMemcpyHostToDevice);
rtBufferSetDevicePointer(buf->get(), 0,(CUdeviceptr)d_test);
m_context["SH_buffer"]->set(buf);
optix::Buffer buf = m_context["SH_buffer"]->getBuffer();
T* d_test;
rtBufferGetDevicePointer(buf->get(), 0,(void**)&d_test);
cudaMemcpy(d_test,p_tab2,width*height*depth*tailleElementaire,cudaMemcpyHostToDevice);
buf->markDirty();

there is no change in the values ​​of the buffer after the call set…

I’m not sure about the sizes you’re using and what p_tab2 is but pay attention to pointers and pointers to pointers, it’s very easy to get confused especially if you’re mixing both OptiX wrappers and native rt* calls.

Aside from this your code seems conceptually correct, here’s a snippet to check out sizes and indirections:

// 1) Create a dummy context
  Context ccontext = Context::create();
  ccontext->setRayTypeCount( 1 );
  ccontext->setEntryPointCount( 1 );

  // 2) Declare a variable, later I will link this to the buffer
  optix::Variable var = ccontext->declareVariable("SH_buffer");

  // 3) Create a buffer to have the device read from it with one 4-float element. NO DATA is allocated or initialized.
  optix::Buffer buf = ccontext->createBufferForCUDA(RT_BUFFER_INPUT,RT_FORMAT_USER,1,1,1);
  buf->setElementSize(sizeof(float));

  // 4) CUDA-initialize our data as we see fit and set the device pointer to the buffer
  void* bufferPtr;
  struct our4Floats {
    float value1;
    float value2;
    float value3;
    float value4;
  } myobj;
  myobj.value1 = 564.9f;
  myobj.value2 = 0.0f;
  myobj.value3 = 0.0f;
  myobj.value4 = 0.0f;

  cudaMalloc((void**)&bufferPtr,4*sizeof(float));
  cudaMemcpy((void*)bufferPtr, (void*)&myobj, 1*sizeof(our4Floats), cudaMemcpyHostToDevice);

  buf->setDevicePointer(0 /*Device 0*/, (CUdeviceptr)bufferPtr);
  ccontext["SH_buffer"]->set(buf);
  buf->markDirty();
  

  // Do something..
  // Initialize and launch..


  // 5) Retrieve our data
  optix::Buffer buf2 = ccontext["SH_buffer"]->getBuffer();
  float result = 0.0f;
  CUdeviceptr retrieveBufAddr;
  retrieveBufAddr = buf2->getDevicePointer(0 /*Device 0*/);
  cudaMemcpy((void*)&result, (void*)retrieveBufAddr, 1*sizeof(float),cudaMemcpyDeviceToHost);
  printf("%f \n", result); // 564.9

  // 6) Change it and retrieve it again
  myobj.value1 = 222.5f;
  cudaMemcpy((void*)retrieveBufAddr, (void*)&myobj, 1*sizeof(our4Floats), cudaMemcpyHostToDevice);
  retrieveBufAddr = buf2->getDevicePointer(0 /*Device 0*/);
  cudaMemcpy((void*)&result, (void*)retrieveBufAddr, 1*sizeof(float),cudaMemcpyDeviceToHost);
  printf("%f \n", result); // 222.5

Hello

thank you for the quick response.

First, I actually had a problem on the pointers.
We must use

CUdeviceptr d_test;
buf->getDevicePointer(0,&d_test);

and not

CUdeviceptr* d_test;
buf->getDevicePointer(0,d_test);

I corrected this error

However, I observed a strange behavior.

Here’s a simple example:

optix::Variable var = m_context->declareVariable("test");
optix::Buffer buf = m_context->createBufferForCUDA(RT_BUFFER_INPUT,RT_FORMAT_USER,1,1,1);
buf->setElementSize(sizeof(float)) ;
float res = 800;
float* d_test;
cudaMalloc((void**)&d_test,sizeof(float));
cudaMemcpy(d_test,(void*)&res,sizeof(float),cudaMemcpyHostToDevice);
buf->setDevicePointer(0,(CUdeviceptr)d_test);
m_context["test"]->set(buf);
buf->markDirty();


CUdeviceptr d_test2;
optix::Buffer buf2 = m_context["test"]->getBuffer();
buf2->getDevicePointer(0,&d_test2);
float ress = 0.f;
cudaMemcpy((void*)&ress,(void*)d_test2,1*sizeof(float),cudaMemcpyDeviceToHost);
printf("%f\n",ress);

The value obtained in ress is 0.

Now, if I add some independent lines, for example:

float* d_test3;
cudaMalloc((void**)&d_test3,sizeof(float));
float res3 = 3;
cudaMemcpy((void*)d_test3,(void*)&res3,1*sizeof(float),cudaMemcpyHostToDevice);

So it gives this

optix::Variable var = m_context->declareVariable("test");
optix::Buffer buf = m_context->createBufferForCUDA(RT_BUFFER_INPUT,RT_FORMAT_USER,1,1,1);
buf->setElementSize(sizeof(float)) ;
float res = 800;
float* d_test;
cudaMalloc((void**)&d_test,sizeof(float));
cudaMemcpy(d_test,(void*)&res,sizeof(float),cudaMemcpyHostToDevice);
buf->setDevicePointer(0,(CUdeviceptr)d_test);
m_context["test"]->set(buf);
buf->markDirty();


float* d_test3;
cudaMalloc((void**)&d_test3,sizeof(float));
float res3 = 3;
cudaMemcpy((void*)d_test3,(void*)&res3,1*sizeof(float),cudaMemcpyHostToDevice);

CUdeviceptr d_test2;
optix::Buffer buf2 = m_context["test"]->getBuffer();
buf2->getDevicePointer(0,&d_test2);
float ress = 0.f;
cudaMemcpy((void*)&ress,(void*)d_test2,1*sizeof(float),cudaMemcpyDeviceToHost);
printf("%f\n",ress);

The value obtained in ress is 3.

Yet in both cases, ress should be worth 800.

I use version 3.0.0 of optix.
Is this a bug or is it me who do not properly use the library ?

In both cases I’m obtaining 800.0 with your same code.

Are you using a valid initialized context? Please check the context for consistency before performing these operations.

As a side note OptiX 3.0.1 was released, you might also update your OptiX version.

thank you for all the answers, I will look to find what is wrong in the context. :-)