在单独线程中渲染图纸

简介

本主题介绍如何在单独的线程中渲染图纸以提高性能。

ODA BimRv SDK 提供了一个简单的 API,用于为 OdBmMTDrawContext、OdBmMTDraw 和 OdBmMTDrawingMgr 类调用多线程功能。

OdBmMTDraw 类通过指定的上下文为单个 OdBmDBDrawing 元素提供线程安全的渲染功能。

OdBmMTDrawingMgr 类通过指定的上下文为 OdBmDBDrawing 元素数组提供线程安全的渲染功能。它只是启动多个 OdBmMTDraw 实例,以在单独的并发线程中渲染绘图数组。

您还需要 OdBmMTDrawContext 或其派生类的一个实例。请参阅下面的类型定义和构造函数:


typedef std::function<OdGsDevicePtr(const OdBmMTDrawContext*)> OdBmCreateGsDeviceFuncType;
typedef std::function<void(OdBmObjectId, OdGsDevice*, const OdBmMTDrawContext*)> OdBmPostProcessFuncType;

OdBmMTDrawContext(
    OdMutex* pDbAccessMutex,
    long picWidth,
    long picHeight,
    bool bZoomToExtents,
    const OdBmCreateGsDeviceFuncType& deviceCreator,
    const OdBmPostProcessFuncType& postProcessor)

最后两个参数是对需要实现的函数的引用。

第一个函数应满足 OdBmCreateGsDeviceFuncType 原型,创建适当的 GS 设备,并返回指向它的指针。

第二个函数应满足 OdBmPostProcessFuncType 原型,并执行渲染结果的后处理。

示例

以下示例通过 GLES2 设备渲染 DBDrawings 并将结果存储在位图数组中。您可以在 BmMTDrawingMgrEx 示例中找到以下代码。

首先,创建 OdBmMTDrawContext 类的派生类。

struct OdBmGLES2MTDrawContext : public OdBmMTDrawContext {
  OdBmGLES2MTDrawContext(
    OdMutex* dbAccessMutex,
    long picWidth,
    long picHeight,
    bool bZoomToExtents,
    const OdBmCreateGsDeviceFuncType& createGsDeviceFunc,
    const OdBmPostProcessFuncType& postProcessFunc,
    // discard back faces wile rendering
    bool bDiscardBackFaces,
    // use plot generation
    bool bPlotGeneration,
    // background color of result images
    ODCOLORREF bgColor = ODRGB(255, 255, 255)):
  OdBmMTDrawContext(
    dbAccessMutex, picWidth, 
    picHeight, bZoomToExtents,
    createGsDeviceFunc, postProcessFunc),
    discardBackFaces(bDiscardBackFaces),
    plotGeneration(bPlotGeneration),
    bgColor(bgColor) {
  }

  bool discardBackFaces;
  ODCOLORREF bgColor;
  bool plotGeneration;
};

接下来,定义一个覆盖类,例如:

class OdBmMTRenderer {
public:
  // type defenition for rendering results
  typedef std::map Renditions; 
  /* execution params
    param drawings - an array of drawings to be rendered.
    param picWidth - width of result bitmaps in pixels.
    param picHeight - height of result bitmaps in pixels.
    param bZoomToExtents - use zoom to extents.
    param bDiscardBackFaces - discard back faces while rendering.
    param bgColor - result bitmaps background color.
  */
  Renditions run(OdBmDBDrawingPtrArray& drawings,
    long picWidth, long picHeight, bool bZoomToExtents = false,
    bool bDiscardBackFaces = false, ODCOLORREF bgColor = ODRGB(255, 255, 255));
};

现在,实现它。首先,获取所有必需的包含文件:

#include "BmMTRenderer.h"

#include "DynamicLinker.h"
#include "RxVariantValue.h"
#include "Gi/GiRasterWrappers.h"
#include "Database/MTDrawingMgr/BmMTDrawingMgr.h"

#include "MTDrawingMgr/BmMTDraw.h"
#include "BmGLES2MTDrawContext.h"

接下来,实现 run() 函数。这是一个专门的过程,因此第一步是创建 OdBmCreateGsDeviceFuncType 类型的函数。

/******************************************************************/
/* GS device creation function                                    */
/******************************************************************/

OdMutex m_createDevice;
auto createDevice = [&m_createDevice](const OdBmMTDrawContext* pContext) {
    TD_AUTOLOCK(m_createDevice);
    const OdBmGLES2MTDrawContext* pToImgContext =
      static_cast(pContext);

    OdGsModulePtr pGsModule = ::odrxDynamicLinker()->loadModule(OdWinGLES2ModuleName);
    OdGsDevicePtr pGsDevice = pGsModule->createBitmapDevice();

    // Enable HLR for Bitmap and WinGDI vectorizers
    OdRxDictionaryPtr pProps = pGsDevice->properties();
    if (pProps->has(OD_T("EnableSoftwareHLR"))) // Check if property is supported
      pProps->putAt(OD_T("EnableSoftwareHLR"), OdRxVariantValue(true));
    if (pProps->has(OD_T("DiscardBackFaces"))) // Check if property is supported
      pProps->putAt(OD_T("DiscardBackFaces"), OdRxVariantValue(pToImgContext->discardBackFaces()));

    OdRxThreadPoolServicePtr pThreadPool = ::odrxDynamicLinker()->loadApp(OdThreadPoolModuleName);
    if (pThreadPool.isNull())
      throw(L"ThreadPool.tx not found.\n");

    OdUInt16 nCPUs = pThreadPool->numCPUs();
    if (pGsDevice->properties()->has(OD_T("MaxRegenThreads")))
      pGsDevice->properties()->putAt(OD_T("MaxRegenThreads"), OdRxVariantValue(nCPUs));

    if (pGsDevice->properties()->has(OD_T("EnableMultithread")))
      pGsDevice->properties()->putAt(OD_T("EnableMultithread"), OdRxVariantValue(true));

    pGsDevice->setLogicalPalette(
      (ODGETRED(pToImgContext->bgColor()) < 140) && (ODGETGREEN(pToImgContext->bgColor()) < 140) && (ODGETBLUE(pToImgContext->bgColor()) < 140) ?
      (::odcmAcadDarkPalette()) : (::odcmAcadLightPalette()), 256);
    pGsDevice->setBackgroundColor(pToImgContext->bgColor());

    return pGsDevice;
};

接下来,创建 OdBmPostProcessFuncType 类型的函数。

/******************************************************************/
/* Rendering results processing function                          */
/******************************************************************/

OdMutex m_mutex;
Renditions renditions;
auto postPrecess = [&m_mutex, &renditions](OdBmObjectId id, OdGsDevice* pDevice, const OdBmMTDrawContext* pContext) {
    TD_AUTOLOCK(m_mutex);
    // Create clone of rendered raster image to correctly release all vectorizer resources in current thread
    OdGiRasterImagePtr pRaster = OdGiRasterImageHolder::createObject(
      OdGiRasterImagePtr(pDevice->properties().get()->getAt(OD_T("RasterImage"))));
    renditions[id] = pRaster;
};

最后,创建 OdBmMTDrawContext 的实例:

/******************************************************************/
/* Instantiate the context and start MT rendering                 */
/******************************************************************/

OdBmGLES2MTDrawContext m_ctx(&m_mutex, picWidth, picHeight, bZoomToExtents,
    (OdBmMTDrawContext::OdBmCreateGsDeviceFuncType)createDevice, 
    (OdBmMTDrawContext::OdBmPostProcessFuncType)postPrecess,
    bDiscardBackFaces, bgColor);
 
OdBmMTDrawingMgr().draw(drawings, &m_ctx);

return renditions;

您可以在 BimRv/Examples/BmMTDrawingMgrEx/BmMTDrawingMgrEx.cpp 文件中找到 run() 方法的实现。

今天就开始行动

免费试用 ODA 软件 60 天。
无风险,无需信用卡。

免费试用