From eadc71b1ae62898ac65f296747ed1e5125f4b96b Mon Sep 17 00:00:00 2001 From: Seneral Date: Sun, 13 Dec 2020 00:30:31 +0000 Subject: [PATCH] Some more debugging for #1 --- camera/gcs.c | 47 ++++++++------ camera/gcs.h | 15 ++++- main_qpu.cpp | 155 +++++++++++++++++++++++++++++----------------- qpu/qpu_program.c | 4 +- 4 files changed, 142 insertions(+), 79 deletions(-) diff --git a/camera/gcs.c b/camera/gcs.c index 77cd9ed..3c8141b 100644 --- a/camera/gcs.c +++ b/camera/gcs.c @@ -90,30 +90,36 @@ GCS *gcs_create(const GCS_CameraParams *cameraParams) CHECK_STATUS_M(mstatus, "Failed to create camera", error_cameraCreate); // Mess with the ISP blocks - uint32_t disableISPBits = 0; -// disableISPBits |= (1 << 2); // Black Level Compensation -// disableISPBits |= (1 << 3); // Lens Shading -// disableISPBits |= (1 << 5); // White Balance Gain -// disableISPBits |= (1 << 7); // Defective Pixel Correction -// disableISPBits |= (1 << 9); // Crosstalk -// disableISPBits |= (1 << 18); // Gamma -// disableISPBits |= (1 << 22); // Sharpening - mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_CAMERA_ISP_BLOCK_OVERRIDE, ~disableISPBits); + // https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=175711 + mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_CAMERA_ISP_BLOCK_OVERRIDE, ~cameraParams->disableISPBlocks); // Enable MMAL camera component mstatus = mmal_component_enable(gcs->camera); CHECK_STATUS_M(mstatus, "Failed to enable camera", error_cameraEnable); // Set camera parameters (See mmal_parameters_camera.h) -// MMAL_PARAMETER_EXPOSUREMODE_T expMode; -// expMode.hdr.id = MMAL_PARAMETER_EXPOSURE_MODE; -// expMode.hdr.size = sizeof(MMAL_PARAMETER_EXPOSUREMODE_T); -// expMode.value = MMAL_PARAM_EXPOSUREMODE_OFF; -// mmal_port_parameter_set(gcs->camera->control, &expMode.hdr); - if (gcs->cameraParams.shutterSpeed != 0) mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_SHUTTER_SPEED, gcs->cameraParams.shutterSpeed); - if (gcs->cameraParams.iso >= 0) mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_ISO, (uint32_t)gcs->cameraParams.iso); -// MMAL_PARAMETER_AWBMODE_T awbMode = { {MMAL_PARAMETER_AWB_MODE,sizeof(awbMode)}, MMAL_PARAM_AWBMODE_SUNLIGHT }; -// mmal_port_parameter_set(gcs->camera->control, &awbMode.hdr); + if (gcs->cameraParams.shutterSpeed != 0) + mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_SHUTTER_SPEED, gcs->cameraParams.shutterSpeed); + if (gcs->cameraParams.iso != 0) + mmal_port_parameter_set_uint32(gcs->camera->control, MMAL_PARAMETER_ISO, (uint32_t)gcs->cameraParams.iso); + if (gcs->cameraParams.disableEXP) + { // Fix Exposure to set ISO value + MMAL_PARAMETER_EXPOSUREMODE_T expMode; + expMode.hdr.id = MMAL_PARAMETER_EXPOSURE_MODE; + expMode.hdr.size = sizeof(MMAL_PARAMETER_EXPOSUREMODE_T); + expMode.value = MMAL_PARAM_EXPOSUREMODE_OFF; + mmal_port_parameter_set(gcs->camera->control, &expMode.hdr); + int expComp = 0; + mmal_port_parameter_set_int32(gcs->camera->control, MMAL_PARAMETER_EXPOSURE_COMP, expComp); + + } + if (gcs->cameraParams.disableAWB) + { // Fix AWB to constant 1,1 gain + MMAL_PARAMETER_AWBMODE_T awbMode = { { MMAL_PARAMETER_AWB_MODE, sizeof(awbMode) }, MMAL_PARAM_AWBMODE_SUNLIGHT }; + mmal_port_parameter_set(gcs->camera->control, &awbMode.hdr); + MMAL_PARAMETER_AWB_GAINS_T awbGains = { { MMAL_PARAMETER_CUSTOM_AWB_GAINS, sizeof(awbGains) }, { 1, 1 }, { 1, 1 }}; + mmal_port_parameter_set(gcs->camera->control, &awbGains.hdr); + } // Enable MMAL camera port gcs->camera->control->userdata = (struct MMAL_PORT_USERDATA_T *)gcs; mstatus = mmal_port_enable(gcs->camera->control, gcs_onCameraControl); @@ -269,6 +275,11 @@ void* gcs_requestFrameBuffer(GCS *gcs) } gcs->processingFrameBuffer = gcs->curFrameBuffer; gcs->curFrameBuffer = NULL; + if (!gcs->processingFrameBuffer) + { // Not cleaned up last frame + LOG_ERROR("No current frame buffer!"); + return NULL; + } return gcs->processingFrameBuffer; } diff --git a/camera/gcs.h b/camera/gcs.h index 22aead3..6a38f59 100644 --- a/camera/gcs.h +++ b/camera/gcs.h @@ -19,9 +19,22 @@ typedef struct GCS_CameraParams uint16_t height; uint16_t fps; uint32_t shutterSpeed; - int32_t iso; + uint32_t iso; + uint8_t disableEXP; + uint8_t disableAWB; + uint32_t disableISPBlocks; } GCS_CameraParams; +/* Disable ISP Blocks */ +// https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=175711 +// (1 << 2); // Black Level Compensation +// (1 << 3); // Lens Shading +// (1 << 5); // White Balance Gain +// (1 << 7); // Defective Pixel Correction +// (1 << 9); // Crosstalk +// (1 << 18); // Gamma +// (1 << 22); // Sharpening +// (1 << 24); // Some Color Conversion /* Opaque GPU Camera Stream structure */ typedef struct GCS GCS; diff --git a/main_qpu.cpp b/main_qpu.cpp index 7e4a996..996f455 100644 --- a/main_qpu.cpp +++ b/main_qpu.cpp @@ -17,24 +17,36 @@ #define TILED 2 // uniforms and setup for tiled frame processing, e.g. blob detection #define BITMSK 3 // uniforms and full frame processing, with bit mask target, e.g. blob detection -#define CAMERA +#define RUN_CAMERA // Have the camera supply frames + // EITHER use emulated buffers with debug content (default) +#define USE_CAMERA // OR use camera frames directly in QPU program +//#define CPY_CAMERA // OR copy copy frames into emulated buffers struct termios terminalSettings; static void setConsoleRawMode(); -uint32_t camWidth = 1280, camHeight = 720, camFPS = 30; - int main(int argc, char **argv) { // ---- Read arguments ---- GCS_CameraParams params = { .mmalEnc = MMAL_ENCODING_I420, - .width = (uint16_t)camWidth, - .height = (uint16_t)camHeight, - .fps = (uint16_t)camFPS, + .width = 1280, + .height = 720, + .fps = 30, .shutterSpeed = 0, - .iso = -1 + .iso = 0, + .disableEXP = false, + .disableAWB = false, + .disableISPBlocks = 0 // https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=175711 +// (1<<2) // Black Level Compensation +// | (1<<3) // Lens Shading +// | (1<<5) // White Balance Gain +// | (1<<7) // Defective Pixel Correction +// | (1<<9) // Crosstalk +// | (1<<18) // Gamma +// | (1<<22) // Sharpening +// | (1<<24) // Some Color Conversion }; char codeFile[64]; uint32_t maxNumFrames = -1; // Enough to run for years @@ -43,7 +55,7 @@ int main(int argc, char **argv) bool enableQPU[12]; int arg; - while ((arg = getopt(argc, argv, "c:w:h:f:s:i:m:o:t:dq:")) != -1) + while ((arg = getopt(argc, argv, "c:w:h:f:s:i:m:o:t:da:e:q:")) != -1) { switch (arg) { @@ -51,13 +63,13 @@ int main(int argc, char **argv) strncpy(codeFile, optarg, sizeof(codeFile)); break; case 'w': - params.width = camWidth = std::stoi(optarg); + params.width = std::stoi(optarg); break; case 'h': - params.height = camHeight = std::stoi(optarg); + params.height = std::stoi(optarg); break; case 'f': - params.fps = camFPS = std::stoi(optarg); + params.fps = std::stoi(optarg); break; case 's': params.shutterSpeed = std::stoi(optarg); @@ -77,11 +89,15 @@ int main(int argc, char **argv) case 'd': drawToFrameBuffer = true; break; + case 'e': + params.disableAWB = true; + break; + case 'x': + params.disableEXP = true; + break; case 'q': for (int i = 0; i < 12 && i < strlen(optarg); i++) - { enableQPU[i] = optarg[i] == '1'; - } default: printf("Usage: %s -c codefile [-w width] [-h height] [-f fps] [-s shutter-speed-ns] [-i iso] [-m mode (full, tiled, bitmsk)] [-d display-to-fb] [-t max-num-frames]\n", argv[0]); break; @@ -125,7 +141,7 @@ int main(int argc, char **argv) // ---- Setup target buffer ---- uint32_t tgtBufferPtr, tgtStride; - uint32_t lineWidth = camWidth, lineCount = camHeight; + uint32_t lineWidth = params.width, lineCount = params.height; int fbfd = 0; struct fb_var_screeninfo orig_vinfo; struct fb_var_screeninfo vinfo; @@ -138,21 +154,25 @@ int main(int argc, char **argv) { tgtStride = finfo.line_length; tgtBufferPtr = finfo.smem_start; - lineWidth = std::min(camWidth, vinfo.xres); - lineCount = std::min(camHeight, vinfo.yres); + if (lineWidth > vinfo.xres || lineCount > vinfo.yres) + { + lineWidth = std::min(lineWidth, vinfo.xres); + lineCount = std::min(lineCount, vinfo.yres); + printf("Limiting resolution to screen while -d is enabled! %dx%d \n", lineWidth, lineCount); + } } } if (!drawToFrameBuffer) { // Allocate buffer to render into - qpu_allocBuffer(&targetBuffer, &base, camWidth*camHeight*4, 4096); - tgtStride = camWidth*4; + qpu_allocBuffer(&targetBuffer, &base, params.width*params.height*4, 4096); + tgtStride = params.width*4; tgtBufferPtr = targetBuffer.ptr.vc; } if (mode == BITMSK) { // Set up bit target, one bit per pixel // Width and height must be multiple of 32 and 16 respectively - lineWidth = (uint32_t)std::floor((float)camWidth/8/4)*8*4; - lineCount = (uint32_t)std::floor((float)camHeight/16)*16; + lineWidth = (uint32_t)std::floor((float)params.width/8/4)*8*4; + lineCount = (uint32_t)std::floor((float)params.height/16)*16; qpu_allocBuffer(&bitmskBuffer, &base, lineWidth/8*lineCount, 4096); tgtStride = lineWidth/8; tgtBufferPtr = bitmskBuffer.ptr.vc; @@ -204,7 +224,7 @@ int main(int argc, char **argv) { // Set up one program to handle the full frame program.progmem.uniforms.arm.uptr[0] = 0; // Enter source pointer each frame program.progmem.uniforms.arm.uptr[1] = tgtBufferPtr; - program.progmem.uniforms.arm.uptr[2] = camWidth; // Source stride + program.progmem.uniforms.arm.uptr[2] = params.width; // Source stride program.progmem.uniforms.arm.uptr[3] = tgtStride; program.progmem.uniforms.arm.uptr[4] = lineWidth; program.progmem.uniforms.arm.uptr[5] = lineCount; @@ -217,7 +237,7 @@ int main(int argc, char **argv) { program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 0] = 0; // Enter source pointer each frame program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 1] = tgtBufferPtr + c*4*8*16 + r*lineCount/splitCols*tgtStride; - program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 2] = camWidth; // Source stride + program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 2] = params.width; // Source stride program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 3] = tgtStride; program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 4] = 8*16; // 16 elements working on 8-pixel columns each program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 5] = lineCount / splitCols; @@ -245,27 +265,10 @@ int main(int argc, char **argv) // QPU scheduler reservation // for (int i = 0; i < 12; i++) // Reset all QPUs to be freely sheduled // qpu_setReservationSetting(&base, i, 0b0000); - - for (int i = 0; i < 12; i++) // Disable ALL QPUs - qpu_setReservationSetting(&base, i, 0b0001); +// for (int i = 0; i < 12; i++) // Disable ALL QPUs +// qpu_setReservationSetting(&base, i, 0b0001); for (int i = 0; i < 12; i++) // Enable only QPUs selected as parameter qpu_setReservationSetting(&base, i, enableQPU[i]? 0b1110 : 0b1111); -// qpu_setReservationSetting(&base, 1, 0b1110); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 9, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 2, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 1, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 4, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 5, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 1, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 3, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 8, 0b0000); // Enable one QPU for user programs -// qpu_setReservationSetting(&base, 5, 0b0000); // Enable one QPU for user programs - -// for (int i = 0; i < 12; i++) // Reserve ALL QPUs for user programs -// qpu_setReservationSetting(&base, i, 0b0000); - -// for (int i = 0; i < numInstances; i++) // Reserve used QPUs for user programs -// qpu_setReservationSetting(&base, i, 0b0000); // for (int i = numInstances; i < 12; i++) // Exempt unused QPUs from user programs // qpu_setReservationSetting(&base, i, 0b0111); qpu_logReservationSettings(&base); @@ -275,7 +278,7 @@ int main(int argc, char **argv) // ---- Setup Camera ---- // Create GPU camera stream (MMAL camera) -#ifdef CAMERA +#ifdef RUN_CAMERA gcs = gcs_create(¶ms); if (gcs == NULL) { @@ -284,18 +287,19 @@ int main(int argc, char **argv) } gcs_start(gcs); printf("-- Camera Stream started --\n"); -#else +#endif +#ifndef USE_CAMERA for (int i = 0; i < emulBufCnt; i++) { - qpu_allocBuffer(&camEmulBuf[i], &base, camWidth*camHeight*3, 4096); // Emulating full YUV frame + qpu_allocBuffer(&camEmulBuf[i], &base, params.width*params.height*3, 4096); // Emulating full YUV frame qpu_lockBuffer(&camEmulBuf[i]); uint8_t *YUVFrameData = (uint8_t*)camEmulBuf[i].ptr.arm.vptr; - for (int x = 0; x < camWidth; x++) + for (int y = 0; y < params.height; y++) { - for (int y = 0; y < camHeight; y++) + for (int x = 0; x < params.width; x++) { // Write test data in Y component (UV are after this, but are not used) - YUVFrameData[y*camWidth + x] = ((x+camWidth/(i+1))*255/camWidth)%256 + ((y+camHeight/(i+1))*255/camHeight)%256; + YUVFrameData[y*params.width + x] = ((x+params.width/(i+1))*255/params.width)%256 + ((y+params.height/(i+1))*255/params.height)%256; } } qpu_unlockBuffer(&camEmulBuf[i]); @@ -310,30 +314,60 @@ int main(int argc, char **argv) lastTime = startTime = std::chrono::high_resolution_clock::now(); while (numFrames < maxNumFrames) { -#ifdef CAMERA +#ifdef RUN_CAMERA // Get most recent MMAL buffer from camera void *cameraBufferHeader = gcs_requestFrameBuffer(gcs); if (!cameraBufferHeader) printf("GCS returned NULL frame! \n"); else #else // Emulate framerate - usleep(std::max(0,(int)(1.0f/camFPS*1000*1000)-4000)); + usleep(std::max(0,(int)(1.0f/params.fps*1000*1000)-4000)); #endif { // ---- Camera Frame Access ---- -#ifdef CAMERA - // Source: https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=167652 +#ifdef RUN_CAMERA // Get buffer data from opaque buffer handle void *cameraBuffer = gcs_getFrameBufferData(cameraBufferHeader); + // Source: https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=167652 // Get VCSM Handle of frameBuffer (works only if zero-copy is enabled, so buffer is in VCSM) uint32_t cameraBufferHandle = vcsm_vc_hdl_from_ptr(cameraBuffer); + #ifndef USE_CAMERA // Lock VCSM buffer to get VC-space address + mem_lock(base.mb, cameraBufferHandle); + + #ifdef CPY_CAMERA + int i = (numFrames)%emulBufCnt; + qpu_lockBuffer(&camEmulBuf[i]); + uint8_t *srcCameraFrame = (uint8_t*)cameraBuffer; + uint8_t *YUVFrameData = (uint8_t*)camEmulBuf[i].ptr.arm.vptr; + for (int y = 0; y < params.height; y++) + { + for (int x = 0; x < params.width; x++) + { + // Write test data in Y component (UV are after this, but are not used) + YUVFrameData[y*params.width + x] = srcCameraFrame[y*params.width+x]; + } + } + qpu_unlockBuffer(&camEmulBuf[i]); + #endif + + #endif +#endif +#ifdef USE_CAMERA uint32_t cameraBufferPtr = mem_lock(base.mb, cameraBufferHandle); #else qpu_lockBuffer(&camEmulBuf[numFrames%emulBufCnt]); uint32_t cameraBufferPtr = camEmulBuf[numFrames%emulBufCnt].ptr.vc; #endif +#ifdef RUN_CAMERA + // Unlock VCSM buffer (no need to keep locked, VC-space adress won't change) +// mem_unlock(base.mb, cameraBufferHandle); + // Return camera buffer to camera +// gcs_returnFrameBuffer(gcs); +#endif + +// usleep(10000); // ---- Uniform preparation ---- @@ -343,7 +377,7 @@ int main(int argc, char **argv) { // Set up individual source pointer for each program instance for (int c = 0; c < numProgCols; c++) for (int r = 0; r < splitCols; r++) - program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 0] = cameraBufferPtr + c*8*16 + r*lineCount/splitCols*camWidth; + program.progmem.uniforms.arm.uptr[c*splitCols*6 + r*6 + 0] = cameraBufferPtr + c*8*16 + r*lineCount/splitCols*params.width; } else { @@ -372,13 +406,15 @@ int main(int argc, char **argv) // Log errors occurred during execution qpu_logErrors(&base); -#ifdef CAMERA +#ifdef USE_CAMERA +#else + qpu_unlockBuffer(&camEmulBuf[numFrames%emulBufCnt]); +#endif +#ifdef RUN_CAMERA // Unlock VCSM buffer (no need to keep locked, VC-space adress won't change) mem_unlock(base.mb, cameraBufferHandle); // Return camera buffer to camera gcs_returnFrameBuffer(gcs); -#else - qpu_unlockBuffer(&camEmulBuf[numFrames%emulBufCnt]); #endif /* // Unlock target buffers @@ -388,8 +424,10 @@ int main(int argc, char **argv) qpu_unlockBuffer(&targetBuffer); */ if (result != 0) + { + printf("Encountered an error after %d frames!\n", numFrames); break; - + } // ---- Debugging and Statistics ---- @@ -468,11 +506,12 @@ int main(int argc, char **argv) } } -#ifdef CAMERA +#ifdef RUN_CAMERA gcs_stop(gcs); gcs_destroy(gcs); printf("-- Camera Stream stopped --\n"); -#else +#endif +#ifndef USE_CAMERA for (int i = 0; i < emulBufCnt; i++) qpu_releaseBuffer(&camEmulBuf[i]); #endif diff --git a/qpu/qpu_program.c b/qpu/qpu_program.c index ba16a41..5d4729a 100644 --- a/qpu/qpu_program.c +++ b/qpu/qpu_program.c @@ -75,8 +75,8 @@ int qpu_executeProgramDirect (QPU_PROGRAM *program, QPU_BASE *base, int numInst, int qpuWaitCount = (qpuQueued + qpuFinished + numInst) % 256; //base->peripheral[V3D_SRQCS] = (1<<7) | (1<<8) | (1<<16); // Reset error bit and counts - if (qpuWaitCount < qpuFinished) - printf("QPU executing %d programs; waiting for %d with %d queued and %d already finished! \n", numInst, qpuWaitCount, qpuQueued, qpuFinished); +// if (qpuWaitCount < qpuFinished) +// printf("QPU executing %d programs; waiting for %d with %d queued and %d already finished! \n", numInst, qpuWaitCount, qpuQueued, qpuFinished); if (perfState != NULL) perfState->qpusUsed = numInst;