的OpenCL/OpenGL的纹理互操作:调整OpenGL纹理

问题描述:

后续这个问题Problems with OpenCL/OpenGL Texture interop/windows的OpenCL/OpenGL的纹理互操作:调整OpenGL纹理

我们:

  • 渲染到FBO,附带作为COLOR_ATTACHMENT0纹理,这是inTex
  • OpenCL中可分离downscaler,使用inTex,通过tempTex
01在一个三步过程中产生

现在出现了一个新问题,因为这是一个编辑器实现。如果inTex的大小发生变化或者outTex的大小发生变化,则首先使用glTexImage2d调整OpenGL纹理的大小。然后释放三个内核对象,最后使用clReleaseMemObj(XTex)发布所有三种纹理的对象。最后一步简单地使用与初始化时相同的代码重新创建所有必需的对象,并继续循环。

在使用clCreateFromGLTexture2D重新创建那些纹理的cl_mem对象时,我收到CL_OUT_OF_RESOURCES。相应地,缩减不再被执行,因为设置纹理内核参数产生CL_INVALID_MEM_OBJECT

也许有些伪代码有助于理解这个问题:

// OBJECTS // 
//////////// 
cl_kernel k_x, k_y, k_clear; 
cl_mem  textureObjects[3]; 
int   src_width, src_height, dst_width, dst_height; 
size_t  rngClr[3], offsClr[3], range_x[3], range_y[3]; 
float  clrCol[4] 

// MAIN ENTRY POINT // 
///////////////////// 
if ((fbo) && calculate()) 
{ 
    glFinish(); 

    if (CL_recreate) recreateCLstuff(); 

    CLmgr->acquireGLObjects(3, textureObjects); 
    CLmgr->callKernel(k_clear, rngClr, offsClr, "clear"); 
    CLmgr->setSimpleKernelArg(k_x, 3, 8, &convertXY, "horizontal::convert"); 
    CLmgr->setSimpleKernelArg(k_x, 4, 16, &offsets_X, "horizontal::offset"); 
    CLmgr->callKernel(k_x, range_x, "horizontal downsample"); 
    CLmgr->setSimpleKernelArg(k_y, 3, 8, &convertXY.m128_f32[ 2 ], "vertical::convert"); 
    CLmgr->setSimpleKernelArg(k_y, 4, 16, &offsets_Y, "vertical::offset"); 
    CLmgr->callKernel(k_y, range_y, "vertical downsample"); 
    CLmgr->releaseGLObjects(3, textureObjects); 
    clFinish(); 
} 

bool calculate() 
{ 
    // check if a resize of the "inTex" happened or a resize of 
    // "outTex" or "tempTex" is necessary 
    int srcw, srch, dstw, dsth; 
    // acquire above values 
    if ((srcw != src_width) || (srch != src_height) || (dstw != dst_width) || (dsth != dst_height)) 
    { 
     CL_recreate = true; 

     // rebuild temporary texture 
     if ((dst_width != dstw) || (src_height != srch)) 
      resizeTemporaryOpenGLTexture(); 
     // rebuild target texture 
     if ((dst_width != dstw) || (dst_height != dsth)) 
      resizeOutputOpenGLTexture(); 

     // finally copy new values to the non-temporary objects 
    } 
    // produce all necessary parameters: 
    // - ranges (rngClr, offsClr, range_x, range_y) 
    // - convertXY 
    // - offsets_X 
    // - offsets_Y 
} 

void recreateCLstuff() 
{ 
    releaseCLstuff(); 
    cerr << name() << ": recreating CL-stuff...\n"; 
    k_x    = CLmgr->newKernelInstance(className(), "separable"); 
    k_y    = CLmgr->newKernelInstance(className(), "separable"); 
    k_clearEmpty = CLmgr->newKernelInstance(className(), "clearEmpty"); 
    k_clear   = CLmgr->newKernelInstance(className(), "clear"); 
    // [...] 
    textureObjects[ 0 ] = CLmgr->createTexture(sourceTexID, WI_CL_TEXTURE_USE::sourceTexture, "source FBO texture"); 
    CLmgr->setMemKernelArg(k_x, 0, textureObjects[ 0 ], "horizontal::src"); 
    textureObjects[ 1 ] = CLmgr->createTexture(tempTexID, WI_CL_TEXTURE_USE::tempTexture, "separable downscaler buffer"); 
    CLmgr->setMemKernelArg(k_x, 1, textureObjects[ 1 ], "horizontal::dst"); 
    CLmgr->setMemKernelArg(k_y, 0, textureObjects[ 1 ], "vertical::src"); 
    textureObjects[ 2 ] = CLmgr->createTexture(textureID, WI_CL_TEXTURE_USE::targetTexture, "WI_CLtexture target"); 
    CLmgr->setMemKernelArg(k_y, 1, textureObjects[ 2 ], "vertical::dst"); 
    CLmgr->setMemKernelArg(k_clear, 1, textureObjects[ 2 ], "clear::dst"); 

    CLmgr->setSimpleKernelArg(k_clear, 0, 16, clrCol, "clear::clearColor"); 

    CL_recreate = false; 
} 

void releaseCLstuff() 
{ 
    cerr << name() << ": releasing CL stuff...\n"; 
    cl_int err; 
    #define releaseKernel(obj) if (obj) if (err = clReleaseKernel(obj)) cerr << "release kernel object \""##obj##"\" failed! (" << clErrorString(err) << ")\n" 

    releaseKernel(k_x); 
    releaseKernel(k_y); 
    releaseKernel(k_clear); 

    for (int i = 0; i < 3; ++i) 
    { 
     if (textureObjects[ i ]) 
      if (err = clReleaseMemObject(textureObjects[ i ])) 
       cerr << "release texture object #" << i << " failed! (" << clErrorString(err) << ")\n"; 
      else 
       textureObjects[ i ] = nullptr; 
    } 
} 

答案很简单:明显的OpenCL不喜欢重复使用一个OpenGL纹理。如果共享纹理的大小发生变化,则需要处理以下步骤:

glDeleteTextures(1, &id); 
glGenTextures(1, &id); 
glBindTexture(GL_TEXTURE_2D, id); 
// set texture parameters, so it becomes complete in the eyes of OpenCL and OpenGL 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
// allocate texture storage in the GPU 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); 
glBindTexture(GL_TEXTURE_2D, 0); 
glFinish(); 

object = clCreateFromGLTexture2D(context, flags[ usage ], GL_TEXTURE_2D, 0, &id, nullptr); 
clSetKernelArg(kernel, argPos, sizeof(cl_mem), &object);