16#include "frontend/GPUDisplayInfo.inc"
25#include <condition_variable>
28#include "../utils/linux_helpers.h"
43#include "helpers/GPUDisplayColors.inc"
45constexpr hmm_mat4 MY_HMM_IDENTITY = {{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}};
51 static GPUSettingsDisplay defaultConfig;
52 return (
chain &&
chain->mConfigDisplay) ? *
chain->mConfigDisplay : defaultConfig;
57 static GPUSettingsProcessing defaultConfig;
61GPUDisplay::GPUDisplay(
GPUDisplayFrontend* frontend,
GPUChainTracking*
chain,
GPUQA* qa,
const GPUParam*
param,
const GPUCalibObjectsConst* calib,
const GPUSettingsDisplay* config,
const GPUSettingsProcessing* proc) :
GPUDisplayInterface(), mFrontend(frontend), mChain(
chain), mConfig(config ? *config : GetConfig(
chain)), mProcessingSettings(proc ? *proc : GetProcessingConfig(
chain)), mQA(qa)
65 mCfgL = mConfig.light;
66 mCfgH = mConfig.heavy;
67 mCfgR = mConfig.renderer;
70 throw std::runtime_error(
"Error obtaining display backend");
72 mBackend->mDisplay =
this;
75 mCfgR.openGLCore = mBackend->CoreProfile();
78void GPUDisplay::calcXYZ(
const float* matrix)
80 mXYZ[0] = -(matrix[0] * matrix[12] + matrix[1] * matrix[13] + matrix[2] * matrix[14]);
81 mXYZ[1] = -(matrix[4] * matrix[12] + matrix[5] * matrix[13] + matrix[6] * matrix[14]);
82 mXYZ[2] = -(matrix[8] * matrix[12] + matrix[9] * matrix[13] + matrix[10] * matrix[14]);
84 mAngle[0] = -asinf(matrix[6]);
85 float A = cosf(mAngle[0]);
86 if (fabsf(
A) > 0.005) {
87 mAngle[1] = atan2f(-matrix[2] /
A, matrix[10] /
A);
88 mAngle[2] = atan2f(matrix[4] /
A, matrix[5] /
A);
91 mAngle[2] = atan2f(-matrix[1], -matrix[0]);
94 mRPhiTheta[0] = sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[1] * mXYZ[1] + mXYZ[2] * mXYZ[2]);
95 mRPhiTheta[1] = atan2f(mXYZ[0], mXYZ[2]);
96 mRPhiTheta[2] = atan2f(mXYZ[1], sqrtf(mXYZ[0] * mXYZ[0] + mXYZ[2] * mXYZ[2]));
98 createQuaternionFromMatrix(mQuat, matrix);
116 mNCollissions = std::max<uint32_t>(mNCollissions, collision + 1);
117 mOverlayTFClusters.resize(mNCollissions);
118 mOverlayTFClusters[collision][sector] = cluster;
121void GPUDisplay::mAnimationCloseAngle(
float& newangle,
float lastAngle)
123 const float delta = lastAngle > newangle ? (2 * CAMath::Pi()) : (-2 *
CAMath::Pi());
124 while (fabsf(newangle + delta - lastAngle) < fabsf(newangle - lastAngle)) {
128void GPUDisplay::mAnimateCloseQuaternion(
float*
v,
float lastx,
float lasty,
float lastz,
float lastw)
130 float distPos2 = (lastx -
v[0]) * (lastx -
v[0]) + (lasty -
v[1]) * (lasty -
v[1]) + (lastz -
v[2]) * (lastz -
v[2]) + (lastw -
v[3]) * (lastw -
v[3]);
131 float distNeg2 = (lastx +
v[0]) * (lastx +
v[0]) + (lasty +
v[1]) * (lasty +
v[1]) + (lastz +
v[2]) * (lastz +
v[2]) + (lastw +
v[3]) * (lastw +
v[3]);
132 if (distPos2 > distNeg2) {
133 for (int32_t
i = 0;
i < 4;
i++) {
154void GPUDisplay::updateConfig()
156 mBackend->setQuality();
157 mBackend->setDepthBuffer();
162 mNDrawCalls += mBackend->drawVertices(
v, t);
167 int32_t
retVal = initFailure;
170 retVal = InitDisplay_internal();
172 }
catch (
const std::runtime_error& e) {
173 GPUError(
"%s", e.what());
176 mInitResult =
retVal == 0 ? 1 : -1;
180int32_t GPUDisplay::InitDisplay_internal()
182 mThreadBuffers.resize(getNumThreads());
183 mThreadTracks.resize(getNumThreads());
184 if (mBackend->InitBackend()) {
187 mYFactor = mBackend->getYFactor();
188 mDrawTextInCompatMode = !mBackend->mFreetypeInitialized && mFrontend->
mCanDrawText == 1;
201 mBackend->ExitBackend();
207 mSemLockDisplay.
Lock();
216 }
else if (!mOverlayTFClusters.size()) {
220 DrawGLScene_internal();
221 }
catch (
const std::runtime_error& e) {
222 GPUError(
"Runtime error %s during display", e.what());
226 if (mLoadAndShowEvent) {
228 std::lock_guard<std::mutex> lock(mMutexLoadAndShowEvent);
229 mLoadAndShowEvent =
false;
231 mCVLoadAndShowEvent.notify_one();
238void GPUDisplay::DrawGLScene_cameraAndAnimation(
float animateTime,
float& mixSlaveImage,
hmm_mat4& nextViewMatrix)
243 bool lookOrigin = mCfgR.camLookOrigin ^ mFrontend->
mKeys[mFrontend->
KEY_ALT];
244 bool yUp = mCfgR.camYUp ^ mFrontend->
mKeys[mFrontend->
KEY_CTRL] ^ lookOrigin;
249 float scalefactor = mFrontend->
mKeys[mFrontend->
KEY_SHIFT] ? 0.2f : 1.0f;
250 float rotatescalefactor = scalefactor * 0.25f;
251 if (mCfgL.drawSector != -1) {
254 float sqrdist = sqrtf(sqrtf(mViewMatrixP[12] * mViewMatrixP[12] + mViewMatrixP[13] * mViewMatrixP[13] + mViewMatrixP[14] * mViewMatrixP[14]) * GL_SCALE_FACTOR) * 0.8f;
255 if (sqrdist < 0.2f) {
261 scalefactor *= sqrdist;
265 if (animateCamera(animateTime, mixSlaveImage, nextViewMatrix)) {
267 }
else if (mResetScene) {
268 const float initialZpos = mCfgH.projectXY ? 16 : (mParam->
par.continuousTracking ? (mMaxClusterZ * GL_SCALE_FACTOR + 8) : 8);
269 nextViewMatrix = nextViewMatrix *
HMM_Translate({{0, 0, -initialZpos}});
273 mCfgL.pointSize = 2.0f;
274 mCfgL.lineWidth = 1.4f;
275 mCfgL.drawSector = -1;
276 mCfgL.showCollision = -1;
277 mCfgH.xAdd = mCfgH.zAdd = 0;
278 mCfgR.camLookOrigin = mCfgR.camYUp =
false;
279 mAngleRollOrigin = -1e9f;
281 mUpdateDrawCommands =
true;
285 float moveZ = scalefactor * ((float)mMouseWheelTmp / 150 + (
float)(mFrontend->
mKeys[(
uint8_t)
'W'] - mFrontend->
mKeys[(uint8_t)
'S']) * (!mFrontend->
mKeys[mFrontend->
KEY_SHIFT]) * 0.2f * mFPSScale);
287 float moveX = scalefactor * ((float)(mFrontend->
mKeys[(uint8_t)
'A'] - mFrontend->
mKeys[(
uint8_t)
'D']) * (!mFrontend->
mKeys[mFrontend->
KEY_SHIFT]) * 0.2f * mFPSScale);
288 float rotRoll = rotatescalefactor * mFPSScale * 2 * (mFrontend->
mKeys[(
uint8_t)
'E'] - mFrontend->
mKeys[(uint8_t)
'F']) * (!mFrontend->
mKeys[mFrontend->
KEY_SHIFT]);
289 float rotYaw = rotatescalefactor * mFPSScale * 2 * (mFrontend->
mKeys[mFrontend->
KEY_RIGHT] - mFrontend->
mKeys[mFrontend->
KEY_LEFT]);
290 float rotPitch = rotatescalefactor * mFPSScale * 2 * (mFrontend->
mKeys[mFrontend->
KEY_DOWN] - mFrontend->
mKeys[mFrontend->
KEY_UP]);
292 float mouseScale = 1920.f / std::max<float>(1920.f, mBackend->mScreenWidth);
294 moveZ += -scalefactor * mouseScale * ((float)mFrontend->
mMouseMvY - (
float)mFrontend->
mMouseDnY) / 4;
295 rotRoll += -rotatescalefactor * mouseScale * ((float)mFrontend->
mMouseMvX - (
float)mFrontend->
mMouseDnX);
297 moveX += scalefactor * 0.5f * mouseScale * ((float)mFrontend->
mMouseDnX - (
float)mFrontend->
mMouseMvX) / 4;
298 moveY += scalefactor * 0.5f * mouseScale * ((float)mFrontend->
mMouseMvY - (
float)mFrontend->
mMouseDnY) / 4;
300 rotYaw += rotatescalefactor * mouseScale * ((float)mFrontend->
mMouseMvX - (
float)mFrontend->
mMouseDnX);
301 rotPitch += rotatescalefactor * mouseScale * ((float)mFrontend->
mMouseMvY - (
float)mFrontend->
mMouseDnY);
305 mAnimationDelay += moveX;
306 if (mAnimationDelay < 0.05f) {
307 mAnimationDelay = 0.05f;
311 SetInfo(
"Animation delay set to %1.2f", mAnimationDelay);
315 mAngleRollOrigin = 0;
316 }
else if (!lookOrigin) {
317 mAngleRollOrigin = -1e6;
321 if (mAngleRollOrigin < -1e6) {
322 mAngleRollOrigin = yUp ? 0.f : -mAngle[2];
324 mAngleRollOrigin += rotRoll;
325 nextViewMatrix = nextViewMatrix *
HMM_Rotate(mAngleRollOrigin, {{0, 0, 1}});
326 float tmpX = moveX, tmpY = moveY;
327 moveX = tmpX * cosf(mAngle[2]) - tmpY * sinf(mAngle[2]);
328 moveY = tmpX * sinf(mAngle[2]) + tmpY * cosf(mAngle[2]);
331 const float x = mXYZ[0],
y = mXYZ[1],
z = mXYZ[2];
332 float r = sqrtf(
x *
x + +
y *
y +
z *
z);
333 float r2 = sqrtf(
x *
x +
z *
z);
334 float phi = atan2f(
z,
x);
336 float theta = atan2f(mXYZ[1], r2);
337 theta -= moveY * 0.1f;
338 const float max_theta = CAMath::Pi() / 2 - 0.01f;
339 if (theta >= max_theta) {
341 }
else if (theta <= -max_theta) {
344 if (moveZ >=
r - 0.1f) {
348 r2 =
r * cosf(theta);
349 mXYZ[0] = r2 * cosf(phi);
350 mXYZ[2] = r2 * sinf(phi);
351 mXYZ[1] =
r * sinf(theta);
356 nextViewMatrix = nextViewMatrix *
HMM_LookAt({{mXYZ[0], mXYZ[1], mXYZ[2]}}, {{0, 0, 0}}, {{0, 1, 0}});
358 nextViewMatrix = nextViewMatrix *
HMM_Translate({{moveX, moveY * mYFactor, moveZ}});
361 nextViewMatrix = nextViewMatrix *
HMM_Rotate(rotYaw, {{0, 1, 0}});
363 if (rotPitch != 0.f) {
364 nextViewMatrix = nextViewMatrix *
HMM_Rotate(rotPitch * mYFactor, {{1, 0, 0}});
366 if (!yUp && rotRoll != 0.f) {
367 nextViewMatrix = nextViewMatrix *
HMM_Rotate(rotRoll * mYFactor, {{0, 0, 1}});
370 nextViewMatrix = nextViewMatrix * mViewMatrix;
372 calcXYZ(&nextViewMatrix.
Elements[0][0]);
373 nextViewMatrix =
HMM_Rotate(mAngle[2] * 180.f / CAMath::Pi(), {{0, 0, 1}}) * nextViewMatrix;
379 if (rotPitch != 0.f) {
382 if (rotRoll != 0.f) {
383 if (rotateModelTPC) {
384 mModelMatrix =
HMM_Rotate(-rotRoll, {{0, 0, 1}}) * mModelMatrix;
393 float minSize = 0.4f / (mCfgR.drawQualityDownsampleFSAA > 1 ? mCfgR.drawQualityDownsampleFSAA : 1);
395 mCfgL.lineWidth += (float)deltaLine * mFPSScale * 0.02f * mCfgL.lineWidth;
396 if (mCfgL.lineWidth <
minSize) {
400 SetInfo(
"%s line width: %f", deltaLine > 0 ?
"Increasing" :
"Decreasing", mCfgL.lineWidth);
401 mUpdateDrawCommands =
true;
405 mCfgL.pointSize += (float)deltaPoint * mFPSScale * 0.02f * mCfgL.pointSize;
406 if (mCfgL.pointSize <
minSize) {
410 SetInfo(
"%s point size: %f", deltaPoint > 0 ?
"Increasing" :
"Decreasing", mCfgL.pointSize);
411 mUpdateDrawCommands =
true;
416 if (animateTime < 0) {
417 mViewMatrix = nextViewMatrix;
418 calcXYZ(mViewMatrixP);
425 if (timer.IsRunning()) {
426 GPUInfo(
"Display Time: Camera:\t\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
430void GPUDisplay::DrawGLScene_drawCommands()
432#define LOOP_SECTOR for (int32_t iSector = (mCfgL.drawSector == -1 ? 0 : mCfgL.drawRelatedSectors ? (mCfgL.drawSector % (NSECTORS / 4)) : mCfgL.drawSector); iSector < NSECTORS; iSector += (mCfgL.drawSector == -1 ? 1 : mCfgL.drawRelatedSectors ? (NSECTORS / 4) : NSECTORS))
433#define LOOP_SECTOR2 for (int32_t iSector = (mCfgL.drawSector == -1 ? 0 : mCfgL.drawRelatedSectors ? (mCfgL.drawSector % (NSECTORS / 4)) : mCfgL.drawSector) % (NSECTORS / 2); iSector < NSECTORS / 2; iSector += (mCfgL.drawSector == -1 ? 1 : mCfgL.drawRelatedSectors ? (NSECTORS / 4) : NSECTORS))
434#define LOOP_COLLISION for (int32_t iCol = (mCfgL.showCollision == -1 ? 0 : mCfgL.showCollision); iCol < mNCollissions; iCol += (mCfgL.showCollision == -1 ? 1 : mNCollissions))
435#define LOOP_COLLISION_COL(cmd) \
438 if (mCfgL.colorCollisions) { \
439 SetCollisionColor(iCol); \
444 if (mCfgL.drawGrid) {
454 if (mCfgL.drawClusters) {
457 mBackend->lineWidthFactor(2);
459 if (mCfgL.drawFinal && mCfgL.colorClusters) {
463 mBackend->lineWidthFactor(1);
467 mBackend->pointSizeFactor(2);
469 mBackend->pointSizeFactor(1);
479 if (mCfgL.drawInitLinks) {
480 if (mCfgL.excludeClusters) {
483 if (mCfgL.colorClusters) {
489 if (mCfgL.drawLinks) {
490 if (mCfgL.excludeClusters) {
493 if (mCfgL.colorClusters) {
501 if (mCfgL.drawSeeds) {
502 if (mCfgL.excludeClusters) {
505 if (mCfgL.colorClusters) {
513 if (mCfgL.drawTracklets) {
514 if (mCfgL.excludeClusters) {
517 if (mCfgL.colorClusters) {
523 if (mCfgL.drawTracks) {
524 if (mCfgL.excludeClusters) {
527 if (mCfgL.colorClusters) {
534 if (mCfgL.drawExtrapolatedTracks) {
535 if (mCfgL.excludeClusters) {
538 if (mCfgL.colorClusters) {
539 SetColorExtrapolatedTracks();
547 if (mCfgL.drawFinal && mCfgL.propagateTracks < 2) {
548 if (mCfgL.excludeClusters) {
551 if (mCfgL.colorClusters) {
560 if (!mCfgH.clustersOnly && mCfgL.excludeClusters != 1) {
562 if (mCfgL.drawInitLinks) {
566 if (mCfgL.drawLinks) {
570 if (mCfgL.drawSeeds) {
574 if (mCfgL.drawTracklets) {
578 if (mCfgL.drawTracks) {
582 if (mCfgL.drawExtrapolatedTracks) {
583 SetColorExtrapolatedTracks();
587 if (mCfgL.drawFinal) {
591 if (mCfgL.colorCollisions) {
592 SetCollisionColor(iCol);
594 if (mCfgL.propagateTracks < 2) {
597 if (mCfgL.propagateTracks > 0 && mCfgL.propagateTracks < 3) {
600 if (mCfgL.propagateTracks == 2) {
603 if (mCfgL.propagateTracks == 3) {
607 if (mCfgH.drawTracksAndFilter ? (mCfgH.drawTPCTracks || mCfgH.drawTRDTracks || mCfgH.drawTOFTracks) : mCfgH.drawITSTracks) {
611 if (mCfgH.markClusters || mCfgH.markAdjacentClusters || mCfgH.markFakeClusters) {
612 if (mCfgH.markFakeClusters) {
613 mBackend->pointSizeFactor(3);
617 if (mCfgH.markFakeClusters) {
618 mBackend->pointSizeFactor(1);
624void GPUDisplay::DrawGLScene_internal(
float animateTime,
bool renderToMixBuffer)
626 bool doScreenshot = (mRequestScreenshot || mAnimateScreenshot) && animateTime < 0;
629 if (animateTime < 0 && (mUpdateEventData || mResetScene || mUpdateVertexLists) && mIOPtrs) {
630 disableUnsupportedOptions();
632 if (mUpdateEventData || mUpdateVertexLists) {
633 mUpdateDrawCommands =
true;
637 if (animateTime < 0 && (mUpdateEventData || mResetScene) && mIOPtrs) {
638 timerDraw.ResetStart();
639 DrawGLScene_updateEventData();
643 mUpdateVertexLists =
true;
644 mUpdateEventData =
false;
648 float mixSlaveImage = 0.f;
649 DrawGLScene_cameraAndAnimation(animateTime, mixSlaveImage, nextViewMatrix);
652 if (mUpdateVertexLists && mIOPtrs) {
653 size_t totalVertizes = DrawGLScene_updateVertexList();
654 if (timerDraw.IsRunning()) {
655 printf(
"Event visualization time: %'d us (vertices %'ld / %'ld bytes)\n", (int32_t)(timerDraw.GetCurrentElapsedTime() * 1000000.), (int64_t)totalVertizes, (int64_t)(totalVertizes *
sizeof(mVertexBuffer[0][0])));
660 nextViewMatrix = nextViewMatrix * mModelMatrix;
661 const float zFar = ((mParam->
par.continuousTracking ? (mMaxClusterZ * GL_SCALE_FACTOR) : 8.f) + 50.f) * 2.f;
663 mBackend->prepareDraw(proj, nextViewMatrix, doScreenshot || mRequestScreenshot, renderToMixBuffer, mixSlaveImage);
664 mBackend->pointSizeFactor(1);
665 mBackend->lineWidthFactor(1);
667 if (mUpdateDrawCommands || mBackend->backendNeedRedraw()) {
669 DrawGLScene_drawCommands();
672 if (mCfgL.drawField) {
673 mBackend->drawField();
676 mUpdateDrawCommands =
false;
677 mUpdateRenderPipeline =
false;
678 mBackend->finishDraw(doScreenshot, renderToMixBuffer, mixSlaveImage);
680 if (animateTime < 0) {
685 float fps = (double)mFramesDoneFPS / fpstime;
687 "FPS: %6.2f (Sector: %d, 1:Clusters %d, 2:Prelinks %d, 3:Links %d, 4:Seeds %d, 5:Tracklets %d, 6:Tracks %d, 7:GTracks %d, 8:Merger %d) (%d frames, %d draw calls) "
688 "(X %1.2f Y %1.2f Z %1.2f / R %1.2f Phi %1.1f Theta %1.1f) / Yaw %1.1f Pitch %1.1f Roll %1.1f)",
689 fps, mCfgL.drawSector, mCfgL.drawClusters, mCfgL.drawInitLinks, mCfgL.drawLinks, mCfgL.drawSeeds, mCfgL.drawTracklets, mCfgL.drawTracks, mCfgL.drawExtrapolatedTracks, mCfgL.drawFinal, mFramesDone, mNDrawCalls, mXYZ[0], mXYZ[1], mXYZ[2], mRPhiTheta[0], mRPhiTheta[1] * 180 / CAMath::Pi(),
690 mRPhiTheta[2] * 180 / CAMath::Pi(), mAngle[1] * 180 / CAMath::Pi(), mAngle[0] * 180 / CAMath::Pi(), mAngle[2] * 180 / CAMath::Pi());
692 if (mPrintInfoText & 2) {
695 if (mFPSScaleadjust++) {
696 mFPSScale = 60 / fps;
702 if (mPrintInfoText & 1) {
707 mBackend->finishFrame(mRequestScreenshot, renderToMixBuffer, mixSlaveImage);
709 mRequestScreenshot =
false;
710 std::vector<char>
pixels = mBackend->getPixels();
711 char tmpFileName[48];
712 if (mAnimateScreenshot) {
713 snprintf(tmpFileName, 48,
"mAnimation%d_%05d.bmp", mAnimationExport, mAnimationFrame);
715 DoScreenshot(mAnimateScreenshot ? tmpFileName : mScreenshotFile.c_str(),
pixels);
724 if (mMaxClusterZ <= 0) {
728 mUpdateEventData =
true;
729 mLoadAndShowEvent =
true;
737 std::unique_lock<std::mutex> lock(mMutexLoadAndShowEvent);
738 while (mLoadAndShowEvent) {
739 mCVLoadAndShowEvent.wait(lock);
745 mLoadAndShowEvent =
true;
749 while (mInitResult == 0) {
752 return (mInitResult != 1);
constexpr hmm_mat4 MY_HMM_IDENTITY
#define LOOP_COLLISION_COL(cmd)
HMM_INLINE hmm_mat4 HMM_Perspective(float FOV, float AspectRatio, float Near, float Far)
HMM_INLINE hmm_mat4 HMM_Translate(hmm_vec3 Translation)
HMM_EXTERN hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)
HMM_EXTERN hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis)
double GetCurrentElapsedTime(bool reset=false)
GPUTrackingInOutPointers & mIOPtrs
const GPUCalibObjectsConst & GetCalib() const
const GPUSettingsProcessing & GetProcessingSettings() const
const GPUParam & GetParam() const
static GPUDisplayBackend * getBackend(const char *type)
static constexpr int32_t KEY_ALT
virtual void getSize(int32_t &width, int32_t &height)
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_RALT
static constexpr int32_t KEY_LEFT
volatile int32_t mNeedUpdate
static constexpr int32_t KEY_CTRL
static constexpr int32_t INIT_WIDTH
static constexpr int32_t KEY_SHIFT
static constexpr int32_t KEY_PAGEUP
GPUDisplayBackend * mBackend
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_RCTRL
GPUDisplay(GPUDisplayFrontend *frontend, GPUChainTracking *chain, GPUQA *qa, const GPUParam *param=nullptr, const GPUCalibObjectsConst *calib=nullptr, const GPUSettingsDisplay *config=nullptr, const GPUSettingsProcessing *proc=nullptr)
void SetCollisionFirstCluster(uint32_t collision, int32_t sector, int32_t cluster) override
int32_t StartDisplay() override
GPUDisplayFrontend * frontend()
void BlockTillNextEvent() override
int32_t InitDisplay(bool initFailure=false)
void ShowNextEvent(const GPUTrackingInOutPointers *ptrs=nullptr) override
void WaitTillEventShown() override
void ResizeScene(int32_t width, int32_t height, bool init=false)
GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar
GLint GLsizei GLsizei height
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
GLdouble GLdouble GLdouble z
uint8_t itsSharedClusterMap uint8_t