| Message ID | 20260618122245.946138-8-bryan.odonoghue@linaro.org |
|---|---|
| State | RFC |
| Headers | show |
| Series |
|
| Related | show |
Bryan O'Donoghue <bryan.odonoghue@linaro.org> writes: > Switch to using GpuIspShaderPassDemosiac as the first instance of our > multi-pass GPUISP implementation. Looks OK at the first glance. > Subsequent patches will move elements of this leviathan into discreet > elements with an objective of eliminating register spill, separation of > concerns and de-spaghettification. > > Code red patches are always best. > > Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> > --- > src/libcamera/egl.cpp | 6 +- > .../software_isp_pipeline_gpu.cpp | 325 +----------------- > .../software_isp/software_isp_pipeline_gpu.h | 41 +-- > 3 files changed, 20 insertions(+), 352 deletions(-) > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp > index 3ea694d7c..4da335a53 100644 > --- a/src/libcamera/egl.cpp > +++ b/src/libcamera/egl.cpp > @@ -153,7 +153,6 @@ int eGL::attachTextureToFBO(eGLImage &eglImage) > int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) > { > EGLint drm_format; > - int ret; > > ASSERT(tid_ == Thread::currentId()); > > @@ -213,10 +212,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > > - if (output) > - ret = attachTextureToFBO(eglImage); > - > - return ret; > + return 0; > } > > /** > diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > index 6f988d672..6f329cf40 100644 > --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > @@ -41,7 +41,7 @@ namespace libcamera { > * \param[in] cm The camera manager > */ > SoftwareIspPipelineGpu::SoftwareIspPipelineGpu(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > - : SoftwareIspPipeline(cm), stats_(std::move(stats)) > + : SoftwareIspPipeline(cm), stats_(std::move(stats)), gpuIspShaderPassDemosiac_(egl_) > { > } > > @@ -109,186 +109,13 @@ int SoftwareIspPipelineGpu::getOutputConfig(PixelFormat outputFormat, DebayerOut > return -EINVAL; > } > > -int SoftwareIspPipelineGpu::getShaderVariableLocations(void) > -{ > - attributeVertex_ = glGetAttribLocation(programId_, "vertexIn"); > - attributeTexture_ = glGetAttribLocation(programId_, "textureIn"); > - > - textureUniformBayerDataIn_ = glGetUniformLocation(programId_, "tex_y"); > - ccmUniformDataIn_ = glGetUniformLocation(programId_, "ccm"); > - blackLevelUniformDataIn_ = glGetUniformLocation(programId_, "blacklevel"); > - gammaUniformDataIn_ = glGetUniformLocation(programId_, "gamma"); > - contrastExpUniformDataIn_ = glGetUniformLocation(programId_, "contrastExp"); > - > - textureUniformStep_ = glGetUniformLocation(programId_, "tex_step"); > - textureUniformSize_ = glGetUniformLocation(programId_, "tex_size"); > - textureUniformStrideFactor_ = glGetUniformLocation(programId_, "stride_factor"); > - textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red"); > - textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); > - > - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ > - << " tex_y " << textureUniformBayerDataIn_ > - << " ccm " << ccmUniformDataIn_ > - << " blacklevel " << blackLevelUniformDataIn_ > - << " gamma " << gammaUniformDataIn_ > - << " contrastExp " << contrastExpUniformDataIn_ > - << " tex_step " << textureUniformStep_ > - << " tex_size " << textureUniformSize_ > - << " stride_factor " << textureUniformStrideFactor_ > - << " tex_bayer_first_red " << textureUniformBayerFirstRed_ > - << " proj_matrix " << textureUniformProjMatrix_; > - return 0; > -} > - > int SoftwareIspPipelineGpu::initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat) > { > - std::vector<std::string> shaderEnv; > - unsigned int fragmentShaderDataLen = 0; > - const unsigned char *fragmentShaderData = 0; > - unsigned int vertexShaderDataLen = 0; > - const unsigned char *vertexShaderData = 0; > - GLenum err; > - > - /* Target gles 100 glsl requires "#version x" as first directive in shader */ > - egl_.pushEnv(shaderEnv, "#version 100"); > - > - /* Specify GL_OES_EGL_image_external */ > - egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); > - > - /* > - * Tell shaders how to re-order output taking account of how the pixels > - * are actually stored by EGL. > - */ > - switch (outputFormat) { > - case formats::ARGB8888: > - case formats::XRGB8888: > - break; > - case formats::ABGR8888: > - case formats::XBGR8888: > - egl_.pushEnv(shaderEnv, "#define SWAP_BLUE"); > - break; > - default: > - LOG(Debayer, Error) << "Unsupported output format"; > - return -EINVAL; > - } > - > - /* Pixel location parameters */ > - glFormat_ = GL_LUMINANCE; > - bytesPerPixel_ = 1; > - shaderStridePixels_ = inputConfig_.stride; > - > - switch (inputFormat) { > - case libcamera::formats::SBGGR8: > - case libcamera::formats::SBGGR10_CSI2P: > - case libcamera::formats::SBGGR12_CSI2P: > - firstRed_x_ = 1.0; > - firstRed_y_ = 1.0; > - break; > - case libcamera::formats::SGBRG8: > - case libcamera::formats::SGBRG10_CSI2P: > - case libcamera::formats::SGBRG12_CSI2P: > - firstRed_x_ = 0.0; > - firstRed_y_ = 1.0; > - break; > - case libcamera::formats::SGRBG8: > - case libcamera::formats::SGRBG10_CSI2P: > - case libcamera::formats::SGRBG12_CSI2P: > - firstRed_x_ = 1.0; > - firstRed_y_ = 0.0; > - break; > - case libcamera::formats::SRGGB8: > - case libcamera::formats::SRGGB10_CSI2P: > - case libcamera::formats::SRGGB12_CSI2P: > - firstRed_x_ = 0.0; > - firstRed_y_ = 0.0; > - break; > - default: > - LOG(Debayer, Error) << "Unsupported input format"; > - return -EINVAL; > - }; > - > - /* Shader selection */ > - switch (inputFormat) { > - case libcamera::formats::SBGGR8: > - case libcamera::formats::SGBRG8: > - case libcamera::formats::SGRBG8: > - case libcamera::formats::SRGGB8: > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - break; > - case libcamera::formats::SBGGR10_CSI2P: > - case libcamera::formats::SGBRG10_CSI2P: > - case libcamera::formats::SGRBG10_CSI2P: > - case libcamera::formats::SRGGB10_CSI2P: > - egl_.pushEnv(shaderEnv, "#define RAW10P"); > - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - glFormat_ = GL_RG; > - bytesPerPixel_ = 2; > - } else { > - fragmentShaderData = bayer_1x_packed_frag; > - fragmentShaderDataLen = bayer_1x_packed_frag_len; > - vertexShaderData = identity_vert; > - vertexShaderDataLen = identity_vert_len; > - shaderStridePixels_ = width_; > - } > - break; > - case libcamera::formats::SBGGR12_CSI2P: > - case libcamera::formats::SGBRG12_CSI2P: > - case libcamera::formats::SGRBG12_CSI2P: > - case libcamera::formats::SRGGB12_CSI2P: > - egl_.pushEnv(shaderEnv, "#define RAW12P"); > - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - glFormat_ = GL_RG; > - bytesPerPixel_ = 2; > - } else { > - fragmentShaderData = bayer_1x_packed_frag; > - fragmentShaderDataLen = bayer_1x_packed_frag_len; > - vertexShaderData = identity_vert; > - vertexShaderDataLen = identity_vert_len; > - shaderStridePixels_ = width_; > - } > - break; > - }; > - > - if (egl_.compileVertexShader(vertexShaderId_, vertexShaderData, vertexShaderDataLen, shaderEnv)) { > - LOG(Debayer, Error) << "Compile vertex shader fail"; > - return -ENODEV; > - } > - utils::scope_exit vShaderGuard([&] { glDeleteShader(vertexShaderId_); }); > - > - if (egl_.compileFragmentShader(fragmentShaderId_, fragmentShaderData, fragmentShaderDataLen, shaderEnv)) { > - LOG(Debayer, Error) << "Compile fragment shader fail"; > - return -ENODEV; > - } > - utils::scope_exit fShaderGuard([&] { glDeleteShader(fragmentShaderId_); }); > + int ret; > > - if (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_)) { > - LOG(Debayer, Error) << "Linking program fail"; > - return -ENODEV; > - } > - > - egl_.dumpShaderSource(vertexShaderId_); > - egl_.dumpShaderSource(fragmentShaderId_); > - > - /* Ensure we set the programId_ */ > - egl_.useProgram(programId_); > - err = glGetError(); > - if (err != GL_NO_ERROR) { > - LOG(Debayer, Error) << "Use program error " << err; > - return -ENODEV; > - } > + ret = gpuIspShaderPassDemosiac_.initShaders(inputFormat, outputFormat); > > - return getShaderVariableLocations(); > + return ret; > } > > int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, > @@ -351,6 +178,12 @@ int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, > */ > stats_->setWindow(Rectangle(window_.size())); > > + /* Configure for one pass */ > + PassConfig rawSensorIn = { inputCfg.size, inputConfig_.stride, inputPixelFormat_, window_ }; > + PassConfig rgbaOut = { outputCfg.size, outputConfig_.stride, outputPixelFormat_, Rectangle(outputSize_) }; > + > + gpuIspShaderPassDemosiac_.configure(rawSensorIn, rgbaOut); > + > return 0; > } > > @@ -388,132 +221,10 @@ SoftwareIspPipelineGpu::strideAndFrameSize(const PixelFormat &outputFormat, cons > return std::make_tuple(stride, stride * size.height); > } > > -void SoftwareIspPipelineGpu::setShaderVariableValues(const DebayerParams ¶ms) > -{ > - /* > - * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats > - * are stored in a GL_LUMINANCE texture. The texture width is > - * equal to the stride. > - */ > - GLfloat firstRed[] = { firstRed_x_, firstRed_y_ }; > - GLfloat imgSize[] = { (GLfloat)width_, > - (GLfloat)height_ }; > - GLfloat Step[] = { static_cast<float>(bytesPerPixel_) / (inputConfig_.stride - 1), > - 1.0f / (height_ - 1) }; > - GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_); > - /* > - * Scale input to output size, keeping the aspect ratio and preferring > - * cropping over black bars. > - */ > - GLfloat scale = std::max((GLfloat)window_.width / width_, > - (GLfloat)window_.height / height_); > - GLfloat trans = -(1.0f - scale); > - GLfloat projMatrix[] = { > - scale, 0, 0, 0, > - 0, scale, 0, 0, > - 0, 0, 1, 0, > - trans, trans, 0, 1 > - }; > - /* Static const coordinates */ > - static const GLfloat vcoordinates[4][2] = { > - { -1.0f, -1.0f }, > - { -1.0f, +1.0f }, > - { +1.0f, +1.0f }, > - { +1.0f, -1.0f }, > - }; > - static const GLfloat tcoordinates[4][2] = { > - { 0.0f, 0.0f }, > - { 0.0f, 1.0f }, > - { 1.0f, 1.0f }, > - { 1.0f, 0.0f }, > - }; > - > - /* vertexIn - bayer_8.vert */ > - glEnableVertexAttribArray(attributeVertex_); > - glVertexAttribPointer(attributeVertex_, 2, GL_FLOAT, GL_TRUE, > - 2 * sizeof(GLfloat), vcoordinates); > - > - /* textureIn - bayer_8.vert */ > - glEnableVertexAttribArray(attributeTexture_); > - glVertexAttribPointer(attributeTexture_, 2, GL_FLOAT, GL_TRUE, > - 2 * sizeof(GLfloat), tcoordinates); > - > - /* > - * Set the sampler2D to the respective texture unit for each texutre > - * To simultaneously sample multiple textures we need to use multiple > - * texture units > - */ > - glUniform1i(textureUniformBayerDataIn_, eglImageBayerIn_->texture_unit_uniform_id_); > - > - /* > - * These values are: > - * firstRed = tex_bayer_first_red - bayer_8.vert > - * imgSize = tex_size - bayer_8.vert > - * step = tex_step - bayer_8.vert > - * Stride = stride_factor identity.vert > - * textureUniformProjMatri = No scaling > - */ > - glUniform2fv(textureUniformBayerFirstRed_, 1, firstRed); > - glUniform2fv(textureUniformSize_, 1, imgSize); > - glUniform2fv(textureUniformStep_, 1, Step); > - glUniform1f(textureUniformStrideFactor_, Stride); > - glUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix); > - > - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ > - << " tex_y " << textureUniformBayerDataIn_ > - << " tex_step " << textureUniformStep_ > - << " tex_size " << textureUniformSize_ > - << " stride_factor " << textureUniformStrideFactor_ > - << " tex_bayer_first_red " << textureUniformBayerFirstRed_; > - > - LOG(Debayer, Debug) << "textureUniformY_ = 0 " > - << " firstRed.x " << firstRed[0] > - << " firstRed.y " << firstRed[1] > - << " textureUniformSize_.width " << imgSize[0] > - << " textureUniformSize_.height " << imgSize[1] > - << " textureUniformStep_.x " << Step[0] > - << " textureUniformStep_.y " << Step[1] > - << " textureUniformStrideFactor_ " << Stride > - << " textureUniformProjMatrix_ " << textureUniformProjMatrix_; > - > - GLfloat ccm[9] = { > - params.combinedMatrix[0][0], > - params.combinedMatrix[0][1], > - params.combinedMatrix[0][2], > - params.combinedMatrix[1][0], > - params.combinedMatrix[1][1], > - params.combinedMatrix[1][2], > - params.combinedMatrix[2][0], > - params.combinedMatrix[2][1], > - params.combinedMatrix[2][2], > - }; > - glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); > - LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; > - > - /* > - * 0 = Red, 1 = Green, 2 = Blue > - */ > - glUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]); > - LOG(Debayer, Debug) << " blackLevelUniformDataIn_ " << blackLevelUniformDataIn_ << " data " << params.blackLevel; > - > - /* > - * Gamma > - */ > - glUniform1f(gammaUniformDataIn_, params.gamma); > - LOG(Debayer, Debug) << " gammaUniformDataIn_ " << gammaUniformDataIn_ << " data " << params.gamma; > - > - /* > - * Contrast > - */ > - glUniform1f(contrastExpUniformDataIn_, params.contrastExp); > - LOG(Debayer, Debug) << " contrastExpUniformDataIn_ " << contrastExpUniformDataIn_ << " data " << params.contrastExp; > - > - return; > -} > - > int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer) > { > bool dmabuf_import_succeeded = false; > + int pipelineResult = 0; > > /* eGL context switch */ > egl_.makeCurrent(); > @@ -540,20 +251,17 @@ int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, > /* Generate the output render framebuffer as render to texture */ > egl_.createOutputDMABufTexture2D(*eglImageRGBAOut_, output->planes()[0].fd.get()); > > - setShaderVariableValues(params); > - glViewport(0, 0, width_, height_); > - glClear(GL_COLOR_BUFFER_BIT); > - glDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS); > + pipelineResult = gpuIspShaderPassDemosiac_.process(*eglImageBayerIn_, *eglImageRGBAOut_, width_, height_, params); > > GLenum err = glGetError(); > if (err != GL_NO_ERROR) { > LOG(eGL, Error) << "Drawing scene fail " << err; > - return -ENODEV; > + pipelineResult = -ENODEV; > } else { > egl_.flushOutput(); > } > > - return 0; > + return pipelineResult; > } > > void SoftwareIspPipelineGpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms) > @@ -623,7 +331,7 @@ int SoftwareIspPipelineGpu::start() > return -EINVAL; > > /* Raw bayer input as texture */ > - eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, inputConfig_.stride / bytesPerPixel_, height_, inputConfig_.stride, GL_TEXTURE0, 0); > + eglImageBayerIn_ = std::make_unique<eGLImage>(gpuIspShaderPassDemosiac_.glFormat_, inputConfig_.stride / gpuIspShaderPassDemosiac_.getBytesPerPixel(), height_, inputConfig_.stride, GL_TEXTURE0, 0); > > /* Texture we will render to */ > eglImageRGBAOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1); > @@ -636,8 +344,7 @@ void SoftwareIspPipelineGpu::stop() > eglImageRGBAOut_.reset(); > eglImageBayerIn_.reset(); > > - if (programId_) > - glDeleteProgram(programId_); > + gpuIspShaderPassDemosiac_.stop(); > } > > SizeRange SoftwareIspPipelineGpu::sizes(PixelFormat inputFormat, const Size &inputSize) > diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.h b/src/libcamera/software_isp/software_isp_pipeline_gpu.h > index f0515d889..6a9df2f04 100644 > --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.h > +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.h > @@ -23,16 +23,12 @@ > #include "libcamera/internal/software_isp/benchmark.h" > #include "libcamera/internal/software_isp/swstats_cpu.h" > > -#include <EGL/egl.h> > -#include <EGL/eglext.h> > -#include <GLES3/gl32.h> > - > #include "software_isp_pipeline.h" > +#include "gpu_pipeline_shader_pass_demosiac.h" > > namespace libcamera { > > #define DEBAYER_EGL_MIN_SIMPLE_RGB_GAIN_TEXTURE_UNITS 4 > -#define DEBAYER_OPENGL_COORDS 4 > > class CameraManager; > > @@ -68,48 +64,17 @@ private: > int processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer); > void configureTexture(GLuint &texture); > > - /* Shader program identifiers */ > - GLuint vertexShaderId_ = 0; > - GLuint fragmentShaderId_ = 0; > - GLuint programId_ = 0; > - > /* Pointer to object representing input texture */ > std::unique_ptr<eGLImage> eglImageBayerIn_; > std::unique_ptr<eGLImage> eglImageRGBAOut_; > > - /* Shader parameters */ > - float firstRed_x_; > - float firstRed_y_; > - GLint attributeVertex_; > - GLint attributeTexture_; > - GLint textureUniformStep_; > - GLint textureUniformSize_; > - GLint textureUniformStrideFactor_; > - GLint textureUniformBayerFirstRed_; > - GLint textureUniformProjMatrix_; > - > - GLint textureUniformBayerDataIn_; > - > - /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ > - GLint ccmUniformDataIn_; > - > - /* Black Level compensation */ > - GLint blackLevelUniformDataIn_; > - > - /* Gamma */ > - GLint gammaUniformDataIn_; > - > - /* Contrast */ > - GLint contrastExpUniformDataIn_; > - > Rectangle window_; > std::unique_ptr<SwStatsCpu> stats_; > eGL egl_; > uint32_t width_; > uint32_t height_; > - GLint glFormat_; > - unsigned int bytesPerPixel_; > - uint32_t shaderStridePixels_; > + > + GpuIspShaderPassDemosiac gpuIspShaderPassDemosiac_; > }; > > } /* namespace libcamera */
Bryan O'Donoghue <bryan.odonoghue@linaro.org> writes: > Switch to using GpuIspShaderPassDemosiac as the first instance of our > multi-pass GPUISP implementation. > > Subsequent patches will move elements of this leviathan into discreet > elements with an objective of eliminating register spill, separation of > concerns and de-spaghettification. > > Code red patches are always best. > > Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> > --- > src/libcamera/egl.cpp | 6 +- > .../software_isp_pipeline_gpu.cpp | 325 +----------------- > .../software_isp/software_isp_pipeline_gpu.h | 41 +-- > 3 files changed, 20 insertions(+), 352 deletions(-) > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp > index 3ea694d7c..4da335a53 100644 > --- a/src/libcamera/egl.cpp > +++ b/src/libcamera/egl.cpp > @@ -153,7 +153,6 @@ int eGL::attachTextureToFBO(eGLImage &eglImage) > int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) `output' becomes unused here. > { > EGLint drm_format; > - int ret; > > ASSERT(tid_ == Thread::currentId()); > > @@ -213,10 +212,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > > - if (output) > - ret = attachTextureToFBO(eglImage); > - > - return ret; > + return 0; > } > > /** > diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > index 6f988d672..6f329cf40 100644 > --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp > @@ -41,7 +41,7 @@ namespace libcamera { > * \param[in] cm The camera manager > */ > SoftwareIspPipelineGpu::SoftwareIspPipelineGpu(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > - : SoftwareIspPipeline(cm), stats_(std::move(stats)) > + : SoftwareIspPipeline(cm), stats_(std::move(stats)), gpuIspShaderPassDemosiac_(egl_) > { > } > > @@ -109,186 +109,13 @@ int SoftwareIspPipelineGpu::getOutputConfig(PixelFormat outputFormat, DebayerOut > return -EINVAL; > } > > -int SoftwareIspPipelineGpu::getShaderVariableLocations(void) > -{ > - attributeVertex_ = glGetAttribLocation(programId_, "vertexIn"); > - attributeTexture_ = glGetAttribLocation(programId_, "textureIn"); > - > - textureUniformBayerDataIn_ = glGetUniformLocation(programId_, "tex_y"); > - ccmUniformDataIn_ = glGetUniformLocation(programId_, "ccm"); > - blackLevelUniformDataIn_ = glGetUniformLocation(programId_, "blacklevel"); > - gammaUniformDataIn_ = glGetUniformLocation(programId_, "gamma"); > - contrastExpUniformDataIn_ = glGetUniformLocation(programId_, "contrastExp"); > - > - textureUniformStep_ = glGetUniformLocation(programId_, "tex_step"); > - textureUniformSize_ = glGetUniformLocation(programId_, "tex_size"); > - textureUniformStrideFactor_ = glGetUniformLocation(programId_, "stride_factor"); > - textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red"); > - textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); > - > - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ > - << " tex_y " << textureUniformBayerDataIn_ > - << " ccm " << ccmUniformDataIn_ > - << " blacklevel " << blackLevelUniformDataIn_ > - << " gamma " << gammaUniformDataIn_ > - << " contrastExp " << contrastExpUniformDataIn_ > - << " tex_step " << textureUniformStep_ > - << " tex_size " << textureUniformSize_ > - << " stride_factor " << textureUniformStrideFactor_ > - << " tex_bayer_first_red " << textureUniformBayerFirstRed_ > - << " proj_matrix " << textureUniformProjMatrix_; > - return 0; > -} > - > int SoftwareIspPipelineGpu::initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat) > { > - std::vector<std::string> shaderEnv; > - unsigned int fragmentShaderDataLen = 0; > - const unsigned char *fragmentShaderData = 0; > - unsigned int vertexShaderDataLen = 0; > - const unsigned char *vertexShaderData = 0; > - GLenum err; > - > - /* Target gles 100 glsl requires "#version x" as first directive in shader */ > - egl_.pushEnv(shaderEnv, "#version 100"); > - > - /* Specify GL_OES_EGL_image_external */ > - egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); > - > - /* > - * Tell shaders how to re-order output taking account of how the pixels > - * are actually stored by EGL. > - */ > - switch (outputFormat) { > - case formats::ARGB8888: > - case formats::XRGB8888: > - break; > - case formats::ABGR8888: > - case formats::XBGR8888: > - egl_.pushEnv(shaderEnv, "#define SWAP_BLUE"); > - break; > - default: > - LOG(Debayer, Error) << "Unsupported output format"; > - return -EINVAL; > - } > - > - /* Pixel location parameters */ > - glFormat_ = GL_LUMINANCE; > - bytesPerPixel_ = 1; > - shaderStridePixels_ = inputConfig_.stride; > - > - switch (inputFormat) { > - case libcamera::formats::SBGGR8: > - case libcamera::formats::SBGGR10_CSI2P: > - case libcamera::formats::SBGGR12_CSI2P: > - firstRed_x_ = 1.0; > - firstRed_y_ = 1.0; > - break; > - case libcamera::formats::SGBRG8: > - case libcamera::formats::SGBRG10_CSI2P: > - case libcamera::formats::SGBRG12_CSI2P: > - firstRed_x_ = 0.0; > - firstRed_y_ = 1.0; > - break; > - case libcamera::formats::SGRBG8: > - case libcamera::formats::SGRBG10_CSI2P: > - case libcamera::formats::SGRBG12_CSI2P: > - firstRed_x_ = 1.0; > - firstRed_y_ = 0.0; > - break; > - case libcamera::formats::SRGGB8: > - case libcamera::formats::SRGGB10_CSI2P: > - case libcamera::formats::SRGGB12_CSI2P: > - firstRed_x_ = 0.0; > - firstRed_y_ = 0.0; > - break; > - default: > - LOG(Debayer, Error) << "Unsupported input format"; > - return -EINVAL; > - }; > - > - /* Shader selection */ > - switch (inputFormat) { > - case libcamera::formats::SBGGR8: > - case libcamera::formats::SGBRG8: > - case libcamera::formats::SGRBG8: > - case libcamera::formats::SRGGB8: > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - break; > - case libcamera::formats::SBGGR10_CSI2P: > - case libcamera::formats::SGBRG10_CSI2P: > - case libcamera::formats::SGRBG10_CSI2P: > - case libcamera::formats::SRGGB10_CSI2P: > - egl_.pushEnv(shaderEnv, "#define RAW10P"); > - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - glFormat_ = GL_RG; > - bytesPerPixel_ = 2; > - } else { > - fragmentShaderData = bayer_1x_packed_frag; > - fragmentShaderDataLen = bayer_1x_packed_frag_len; > - vertexShaderData = identity_vert; > - vertexShaderDataLen = identity_vert_len; > - shaderStridePixels_ = width_; > - } > - break; > - case libcamera::formats::SBGGR12_CSI2P: > - case libcamera::formats::SGBRG12_CSI2P: > - case libcamera::formats::SGRBG12_CSI2P: > - case libcamera::formats::SRGGB12_CSI2P: > - egl_.pushEnv(shaderEnv, "#define RAW12P"); > - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { > - fragmentShaderData = bayer_unpacked_frag; > - fragmentShaderDataLen = bayer_unpacked_frag_len; > - vertexShaderData = bayer_unpacked_vert; > - vertexShaderDataLen = bayer_unpacked_vert_len; > - glFormat_ = GL_RG; > - bytesPerPixel_ = 2; > - } else { > - fragmentShaderData = bayer_1x_packed_frag; > - fragmentShaderDataLen = bayer_1x_packed_frag_len; > - vertexShaderData = identity_vert; > - vertexShaderDataLen = identity_vert_len; > - shaderStridePixels_ = width_; > - } > - break; > - }; > - > - if (egl_.compileVertexShader(vertexShaderId_, vertexShaderData, vertexShaderDataLen, shaderEnv)) { > - LOG(Debayer, Error) << "Compile vertex shader fail"; > - return -ENODEV; > - } > - utils::scope_exit vShaderGuard([&] { glDeleteShader(vertexShaderId_); }); > - > - if (egl_.compileFragmentShader(fragmentShaderId_, fragmentShaderData, fragmentShaderDataLen, shaderEnv)) { > - LOG(Debayer, Error) << "Compile fragment shader fail"; > - return -ENODEV; > - } > - utils::scope_exit fShaderGuard([&] { glDeleteShader(fragmentShaderId_); }); > + int ret; > > - if (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_)) { > - LOG(Debayer, Error) << "Linking program fail"; > - return -ENODEV; > - } > - > - egl_.dumpShaderSource(vertexShaderId_); > - egl_.dumpShaderSource(fragmentShaderId_); > - > - /* Ensure we set the programId_ */ > - egl_.useProgram(programId_); > - err = glGetError(); > - if (err != GL_NO_ERROR) { > - LOG(Debayer, Error) << "Use program error " << err; > - return -ENODEV; > - } > + ret = gpuIspShaderPassDemosiac_.initShaders(inputFormat, outputFormat); > > - return getShaderVariableLocations(); > + return ret; > } > > int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, > @@ -351,6 +178,12 @@ int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, > */ > stats_->setWindow(Rectangle(window_.size())); > > + /* Configure for one pass */ > + PassConfig rawSensorIn = { inputCfg.size, inputConfig_.stride, inputPixelFormat_, window_ }; > + PassConfig rgbaOut = { outputCfg.size, outputConfig_.stride, outputPixelFormat_, Rectangle(outputSize_) }; > + > + gpuIspShaderPassDemosiac_.configure(rawSensorIn, rgbaOut); > + > return 0; > } > > @@ -388,132 +221,10 @@ SoftwareIspPipelineGpu::strideAndFrameSize(const PixelFormat &outputFormat, cons > return std::make_tuple(stride, stride * size.height); > } > > -void SoftwareIspPipelineGpu::setShaderVariableValues(const DebayerParams ¶ms) > -{ > - /* > - * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats > - * are stored in a GL_LUMINANCE texture. The texture width is > - * equal to the stride. > - */ > - GLfloat firstRed[] = { firstRed_x_, firstRed_y_ }; > - GLfloat imgSize[] = { (GLfloat)width_, > - (GLfloat)height_ }; > - GLfloat Step[] = { static_cast<float>(bytesPerPixel_) / (inputConfig_.stride - 1), > - 1.0f / (height_ - 1) }; > - GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_); > - /* > - * Scale input to output size, keeping the aspect ratio and preferring > - * cropping over black bars. > - */ > - GLfloat scale = std::max((GLfloat)window_.width / width_, > - (GLfloat)window_.height / height_); > - GLfloat trans = -(1.0f - scale); > - GLfloat projMatrix[] = { > - scale, 0, 0, 0, > - 0, scale, 0, 0, > - 0, 0, 1, 0, > - trans, trans, 0, 1 > - }; > - /* Static const coordinates */ > - static const GLfloat vcoordinates[4][2] = { > - { -1.0f, -1.0f }, > - { -1.0f, +1.0f }, > - { +1.0f, +1.0f }, > - { +1.0f, -1.0f }, > - }; > - static const GLfloat tcoordinates[4][2] = { > - { 0.0f, 0.0f }, > - { 0.0f, 1.0f }, > - { 1.0f, 1.0f }, > - { 1.0f, 0.0f }, > - }; > - > - /* vertexIn - bayer_8.vert */ > - glEnableVertexAttribArray(attributeVertex_); > - glVertexAttribPointer(attributeVertex_, 2, GL_FLOAT, GL_TRUE, > - 2 * sizeof(GLfloat), vcoordinates); > - > - /* textureIn - bayer_8.vert */ > - glEnableVertexAttribArray(attributeTexture_); > - glVertexAttribPointer(attributeTexture_, 2, GL_FLOAT, GL_TRUE, > - 2 * sizeof(GLfloat), tcoordinates); > - > - /* > - * Set the sampler2D to the respective texture unit for each texutre > - * To simultaneously sample multiple textures we need to use multiple > - * texture units > - */ > - glUniform1i(textureUniformBayerDataIn_, eglImageBayerIn_->texture_unit_uniform_id_); > - > - /* > - * These values are: > - * firstRed = tex_bayer_first_red - bayer_8.vert > - * imgSize = tex_size - bayer_8.vert > - * step = tex_step - bayer_8.vert > - * Stride = stride_factor identity.vert > - * textureUniformProjMatri = No scaling > - */ > - glUniform2fv(textureUniformBayerFirstRed_, 1, firstRed); > - glUniform2fv(textureUniformSize_, 1, imgSize); > - glUniform2fv(textureUniformStep_, 1, Step); > - glUniform1f(textureUniformStrideFactor_, Stride); > - glUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix); > - > - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ > - << " tex_y " << textureUniformBayerDataIn_ > - << " tex_step " << textureUniformStep_ > - << " tex_size " << textureUniformSize_ > - << " stride_factor " << textureUniformStrideFactor_ > - << " tex_bayer_first_red " << textureUniformBayerFirstRed_; > - > - LOG(Debayer, Debug) << "textureUniformY_ = 0 " > - << " firstRed.x " << firstRed[0] > - << " firstRed.y " << firstRed[1] > - << " textureUniformSize_.width " << imgSize[0] > - << " textureUniformSize_.height " << imgSize[1] > - << " textureUniformStep_.x " << Step[0] > - << " textureUniformStep_.y " << Step[1] > - << " textureUniformStrideFactor_ " << Stride > - << " textureUniformProjMatrix_ " << textureUniformProjMatrix_; > - > - GLfloat ccm[9] = { > - params.combinedMatrix[0][0], > - params.combinedMatrix[0][1], > - params.combinedMatrix[0][2], > - params.combinedMatrix[1][0], > - params.combinedMatrix[1][1], > - params.combinedMatrix[1][2], > - params.combinedMatrix[2][0], > - params.combinedMatrix[2][1], > - params.combinedMatrix[2][2], > - }; > - glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); > - LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; > - > - /* > - * 0 = Red, 1 = Green, 2 = Blue > - */ > - glUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]); > - LOG(Debayer, Debug) << " blackLevelUniformDataIn_ " << blackLevelUniformDataIn_ << " data " << params.blackLevel; > - > - /* > - * Gamma > - */ > - glUniform1f(gammaUniformDataIn_, params.gamma); > - LOG(Debayer, Debug) << " gammaUniformDataIn_ " << gammaUniformDataIn_ << " data " << params.gamma; > - > - /* > - * Contrast > - */ > - glUniform1f(contrastExpUniformDataIn_, params.contrastExp); > - LOG(Debayer, Debug) << " contrastExpUniformDataIn_ " << contrastExpUniformDataIn_ << " data " << params.contrastExp; > - > - return; > -} > - > int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer) > { > bool dmabuf_import_succeeded = false; > + int pipelineResult = 0; > > /* eGL context switch */ > egl_.makeCurrent(); > @@ -540,20 +251,17 @@ int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, > /* Generate the output render framebuffer as render to texture */ > egl_.createOutputDMABufTexture2D(*eglImageRGBAOut_, output->planes()[0].fd.get()); > > - setShaderVariableValues(params); > - glViewport(0, 0, width_, height_); > - glClear(GL_COLOR_BUFFER_BIT); > - glDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS); > + pipelineResult = gpuIspShaderPassDemosiac_.process(*eglImageBayerIn_, *eglImageRGBAOut_, width_, height_, params); > > GLenum err = glGetError(); > if (err != GL_NO_ERROR) { > LOG(eGL, Error) << "Drawing scene fail " << err; > - return -ENODEV; > + pipelineResult = -ENODEV; > } else { > egl_.flushOutput(); > } > > - return 0; > + return pipelineResult; > } > > void SoftwareIspPipelineGpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms) > @@ -623,7 +331,7 @@ int SoftwareIspPipelineGpu::start() > return -EINVAL; > > /* Raw bayer input as texture */ > - eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, inputConfig_.stride / bytesPerPixel_, height_, inputConfig_.stride, GL_TEXTURE0, 0); > + eglImageBayerIn_ = std::make_unique<eGLImage>(gpuIspShaderPassDemosiac_.glFormat_, inputConfig_.stride / gpuIspShaderPassDemosiac_.getBytesPerPixel(), height_, inputConfig_.stride, GL_TEXTURE0, 0); > > /* Texture we will render to */ > eglImageRGBAOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1); > @@ -636,8 +344,7 @@ void SoftwareIspPipelineGpu::stop() > eglImageRGBAOut_.reset(); > eglImageBayerIn_.reset(); > > - if (programId_) > - glDeleteProgram(programId_); > + gpuIspShaderPassDemosiac_.stop(); > } > > SizeRange SoftwareIspPipelineGpu::sizes(PixelFormat inputFormat, const Size &inputSize) > diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.h b/src/libcamera/software_isp/software_isp_pipeline_gpu.h > index f0515d889..6a9df2f04 100644 > --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.h > +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.h > @@ -23,16 +23,12 @@ > #include "libcamera/internal/software_isp/benchmark.h" > #include "libcamera/internal/software_isp/swstats_cpu.h" > > -#include <EGL/egl.h> > -#include <EGL/eglext.h> > -#include <GLES3/gl32.h> > - > #include "software_isp_pipeline.h" > +#include "gpu_pipeline_shader_pass_demosiac.h" > > namespace libcamera { > > #define DEBAYER_EGL_MIN_SIMPLE_RGB_GAIN_TEXTURE_UNITS 4 > -#define DEBAYER_OPENGL_COORDS 4 > > class CameraManager; > > @@ -68,48 +64,17 @@ private: > int processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer); > void configureTexture(GLuint &texture); > > - /* Shader program identifiers */ > - GLuint vertexShaderId_ = 0; > - GLuint fragmentShaderId_ = 0; > - GLuint programId_ = 0; > - > /* Pointer to object representing input texture */ > std::unique_ptr<eGLImage> eglImageBayerIn_; > std::unique_ptr<eGLImage> eglImageRGBAOut_; > > - /* Shader parameters */ > - float firstRed_x_; > - float firstRed_y_; > - GLint attributeVertex_; > - GLint attributeTexture_; > - GLint textureUniformStep_; > - GLint textureUniformSize_; > - GLint textureUniformStrideFactor_; > - GLint textureUniformBayerFirstRed_; > - GLint textureUniformProjMatrix_; > - > - GLint textureUniformBayerDataIn_; > - > - /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ > - GLint ccmUniformDataIn_; > - > - /* Black Level compensation */ > - GLint blackLevelUniformDataIn_; > - > - /* Gamma */ > - GLint gammaUniformDataIn_; > - > - /* Contrast */ > - GLint contrastExpUniformDataIn_; > - > Rectangle window_; > std::unique_ptr<SwStatsCpu> stats_; > eGL egl_; > uint32_t width_; > uint32_t height_; > - GLint glFormat_; > - unsigned int bytesPerPixel_; > - uint32_t shaderStridePixels_; > + > + GpuIspShaderPassDemosiac gpuIspShaderPassDemosiac_; > }; > > } /* namespace libcamera */
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index 3ea694d7c..4da335a53 100644 --- a/src/libcamera/egl.cpp +++ b/src/libcamera/egl.cpp @@ -153,7 +153,6 @@ int eGL::attachTextureToFBO(eGLImage &eglImage) int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) { EGLint drm_format; - int ret; ASSERT(tid_ == Thread::currentId()); @@ -213,10 +212,7 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (output) - ret = attachTextureToFBO(eglImage); - - return ret; + return 0; } /** diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp index 6f988d672..6f329cf40 100644 --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp @@ -41,7 +41,7 @@ namespace libcamera { * \param[in] cm The camera manager */ SoftwareIspPipelineGpu::SoftwareIspPipelineGpu(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) - : SoftwareIspPipeline(cm), stats_(std::move(stats)) + : SoftwareIspPipeline(cm), stats_(std::move(stats)), gpuIspShaderPassDemosiac_(egl_) { } @@ -109,186 +109,13 @@ int SoftwareIspPipelineGpu::getOutputConfig(PixelFormat outputFormat, DebayerOut return -EINVAL; } -int SoftwareIspPipelineGpu::getShaderVariableLocations(void) -{ - attributeVertex_ = glGetAttribLocation(programId_, "vertexIn"); - attributeTexture_ = glGetAttribLocation(programId_, "textureIn"); - - textureUniformBayerDataIn_ = glGetUniformLocation(programId_, "tex_y"); - ccmUniformDataIn_ = glGetUniformLocation(programId_, "ccm"); - blackLevelUniformDataIn_ = glGetUniformLocation(programId_, "blacklevel"); - gammaUniformDataIn_ = glGetUniformLocation(programId_, "gamma"); - contrastExpUniformDataIn_ = glGetUniformLocation(programId_, "contrastExp"); - - textureUniformStep_ = glGetUniformLocation(programId_, "tex_step"); - textureUniformSize_ = glGetUniformLocation(programId_, "tex_size"); - textureUniformStrideFactor_ = glGetUniformLocation(programId_, "stride_factor"); - textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red"); - textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); - - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ - << " tex_y " << textureUniformBayerDataIn_ - << " ccm " << ccmUniformDataIn_ - << " blacklevel " << blackLevelUniformDataIn_ - << " gamma " << gammaUniformDataIn_ - << " contrastExp " << contrastExpUniformDataIn_ - << " tex_step " << textureUniformStep_ - << " tex_size " << textureUniformSize_ - << " stride_factor " << textureUniformStrideFactor_ - << " tex_bayer_first_red " << textureUniformBayerFirstRed_ - << " proj_matrix " << textureUniformProjMatrix_; - return 0; -} - int SoftwareIspPipelineGpu::initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat) { - std::vector<std::string> shaderEnv; - unsigned int fragmentShaderDataLen = 0; - const unsigned char *fragmentShaderData = 0; - unsigned int vertexShaderDataLen = 0; - const unsigned char *vertexShaderData = 0; - GLenum err; - - /* Target gles 100 glsl requires "#version x" as first directive in shader */ - egl_.pushEnv(shaderEnv, "#version 100"); - - /* Specify GL_OES_EGL_image_external */ - egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); - - /* - * Tell shaders how to re-order output taking account of how the pixels - * are actually stored by EGL. - */ - switch (outputFormat) { - case formats::ARGB8888: - case formats::XRGB8888: - break; - case formats::ABGR8888: - case formats::XBGR8888: - egl_.pushEnv(shaderEnv, "#define SWAP_BLUE"); - break; - default: - LOG(Debayer, Error) << "Unsupported output format"; - return -EINVAL; - } - - /* Pixel location parameters */ - glFormat_ = GL_LUMINANCE; - bytesPerPixel_ = 1; - shaderStridePixels_ = inputConfig_.stride; - - switch (inputFormat) { - case libcamera::formats::SBGGR8: - case libcamera::formats::SBGGR10_CSI2P: - case libcamera::formats::SBGGR12_CSI2P: - firstRed_x_ = 1.0; - firstRed_y_ = 1.0; - break; - case libcamera::formats::SGBRG8: - case libcamera::formats::SGBRG10_CSI2P: - case libcamera::formats::SGBRG12_CSI2P: - firstRed_x_ = 0.0; - firstRed_y_ = 1.0; - break; - case libcamera::formats::SGRBG8: - case libcamera::formats::SGRBG10_CSI2P: - case libcamera::formats::SGRBG12_CSI2P: - firstRed_x_ = 1.0; - firstRed_y_ = 0.0; - break; - case libcamera::formats::SRGGB8: - case libcamera::formats::SRGGB10_CSI2P: - case libcamera::formats::SRGGB12_CSI2P: - firstRed_x_ = 0.0; - firstRed_y_ = 0.0; - break; - default: - LOG(Debayer, Error) << "Unsupported input format"; - return -EINVAL; - }; - - /* Shader selection */ - switch (inputFormat) { - case libcamera::formats::SBGGR8: - case libcamera::formats::SGBRG8: - case libcamera::formats::SGRBG8: - case libcamera::formats::SRGGB8: - fragmentShaderData = bayer_unpacked_frag; - fragmentShaderDataLen = bayer_unpacked_frag_len; - vertexShaderData = bayer_unpacked_vert; - vertexShaderDataLen = bayer_unpacked_vert_len; - break; - case libcamera::formats::SBGGR10_CSI2P: - case libcamera::formats::SGBRG10_CSI2P: - case libcamera::formats::SGRBG10_CSI2P: - case libcamera::formats::SRGGB10_CSI2P: - egl_.pushEnv(shaderEnv, "#define RAW10P"); - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { - fragmentShaderData = bayer_unpacked_frag; - fragmentShaderDataLen = bayer_unpacked_frag_len; - vertexShaderData = bayer_unpacked_vert; - vertexShaderDataLen = bayer_unpacked_vert_len; - glFormat_ = GL_RG; - bytesPerPixel_ = 2; - } else { - fragmentShaderData = bayer_1x_packed_frag; - fragmentShaderDataLen = bayer_1x_packed_frag_len; - vertexShaderData = identity_vert; - vertexShaderDataLen = identity_vert_len; - shaderStridePixels_ = width_; - } - break; - case libcamera::formats::SBGGR12_CSI2P: - case libcamera::formats::SGBRG12_CSI2P: - case libcamera::formats::SGRBG12_CSI2P: - case libcamera::formats::SRGGB12_CSI2P: - egl_.pushEnv(shaderEnv, "#define RAW12P"); - if (BayerFormat::fromPixelFormat(inputFormat).packing == BayerFormat::Packing::None) { - fragmentShaderData = bayer_unpacked_frag; - fragmentShaderDataLen = bayer_unpacked_frag_len; - vertexShaderData = bayer_unpacked_vert; - vertexShaderDataLen = bayer_unpacked_vert_len; - glFormat_ = GL_RG; - bytesPerPixel_ = 2; - } else { - fragmentShaderData = bayer_1x_packed_frag; - fragmentShaderDataLen = bayer_1x_packed_frag_len; - vertexShaderData = identity_vert; - vertexShaderDataLen = identity_vert_len; - shaderStridePixels_ = width_; - } - break; - }; - - if (egl_.compileVertexShader(vertexShaderId_, vertexShaderData, vertexShaderDataLen, shaderEnv)) { - LOG(Debayer, Error) << "Compile vertex shader fail"; - return -ENODEV; - } - utils::scope_exit vShaderGuard([&] { glDeleteShader(vertexShaderId_); }); - - if (egl_.compileFragmentShader(fragmentShaderId_, fragmentShaderData, fragmentShaderDataLen, shaderEnv)) { - LOG(Debayer, Error) << "Compile fragment shader fail"; - return -ENODEV; - } - utils::scope_exit fShaderGuard([&] { glDeleteShader(fragmentShaderId_); }); + int ret; - if (egl_.linkProgram(programId_, vertexShaderId_, fragmentShaderId_)) { - LOG(Debayer, Error) << "Linking program fail"; - return -ENODEV; - } - - egl_.dumpShaderSource(vertexShaderId_); - egl_.dumpShaderSource(fragmentShaderId_); - - /* Ensure we set the programId_ */ - egl_.useProgram(programId_); - err = glGetError(); - if (err != GL_NO_ERROR) { - LOG(Debayer, Error) << "Use program error " << err; - return -ENODEV; - } + ret = gpuIspShaderPassDemosiac_.initShaders(inputFormat, outputFormat); - return getShaderVariableLocations(); + return ret; } int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, @@ -351,6 +178,12 @@ int SoftwareIspPipelineGpu::configure(const StreamConfiguration &inputCfg, */ stats_->setWindow(Rectangle(window_.size())); + /* Configure for one pass */ + PassConfig rawSensorIn = { inputCfg.size, inputConfig_.stride, inputPixelFormat_, window_ }; + PassConfig rgbaOut = { outputCfg.size, outputConfig_.stride, outputPixelFormat_, Rectangle(outputSize_) }; + + gpuIspShaderPassDemosiac_.configure(rawSensorIn, rgbaOut); + return 0; } @@ -388,132 +221,10 @@ SoftwareIspPipelineGpu::strideAndFrameSize(const PixelFormat &outputFormat, cons return std::make_tuple(stride, stride * size.height); } -void SoftwareIspPipelineGpu::setShaderVariableValues(const DebayerParams ¶ms) -{ - /* - * Raw Bayer 8-bit, and packed raw Bayer 10-bit/12-bit formats - * are stored in a GL_LUMINANCE texture. The texture width is - * equal to the stride. - */ - GLfloat firstRed[] = { firstRed_x_, firstRed_y_ }; - GLfloat imgSize[] = { (GLfloat)width_, - (GLfloat)height_ }; - GLfloat Step[] = { static_cast<float>(bytesPerPixel_) / (inputConfig_.stride - 1), - 1.0f / (height_ - 1) }; - GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_); - /* - * Scale input to output size, keeping the aspect ratio and preferring - * cropping over black bars. - */ - GLfloat scale = std::max((GLfloat)window_.width / width_, - (GLfloat)window_.height / height_); - GLfloat trans = -(1.0f - scale); - GLfloat projMatrix[] = { - scale, 0, 0, 0, - 0, scale, 0, 0, - 0, 0, 1, 0, - trans, trans, 0, 1 - }; - /* Static const coordinates */ - static const GLfloat vcoordinates[4][2] = { - { -1.0f, -1.0f }, - { -1.0f, +1.0f }, - { +1.0f, +1.0f }, - { +1.0f, -1.0f }, - }; - static const GLfloat tcoordinates[4][2] = { - { 0.0f, 0.0f }, - { 0.0f, 1.0f }, - { 1.0f, 1.0f }, - { 1.0f, 0.0f }, - }; - - /* vertexIn - bayer_8.vert */ - glEnableVertexAttribArray(attributeVertex_); - glVertexAttribPointer(attributeVertex_, 2, GL_FLOAT, GL_TRUE, - 2 * sizeof(GLfloat), vcoordinates); - - /* textureIn - bayer_8.vert */ - glEnableVertexAttribArray(attributeTexture_); - glVertexAttribPointer(attributeTexture_, 2, GL_FLOAT, GL_TRUE, - 2 * sizeof(GLfloat), tcoordinates); - - /* - * Set the sampler2D to the respective texture unit for each texutre - * To simultaneously sample multiple textures we need to use multiple - * texture units - */ - glUniform1i(textureUniformBayerDataIn_, eglImageBayerIn_->texture_unit_uniform_id_); - - /* - * These values are: - * firstRed = tex_bayer_first_red - bayer_8.vert - * imgSize = tex_size - bayer_8.vert - * step = tex_step - bayer_8.vert - * Stride = stride_factor identity.vert - * textureUniformProjMatri = No scaling - */ - glUniform2fv(textureUniformBayerFirstRed_, 1, firstRed); - glUniform2fv(textureUniformSize_, 1, imgSize); - glUniform2fv(textureUniformStep_, 1, Step); - glUniform1f(textureUniformStrideFactor_, Stride); - glUniformMatrix4fv(textureUniformProjMatrix_, 1, GL_FALSE, projMatrix); - - LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ - << " tex_y " << textureUniformBayerDataIn_ - << " tex_step " << textureUniformStep_ - << " tex_size " << textureUniformSize_ - << " stride_factor " << textureUniformStrideFactor_ - << " tex_bayer_first_red " << textureUniformBayerFirstRed_; - - LOG(Debayer, Debug) << "textureUniformY_ = 0 " - << " firstRed.x " << firstRed[0] - << " firstRed.y " << firstRed[1] - << " textureUniformSize_.width " << imgSize[0] - << " textureUniformSize_.height " << imgSize[1] - << " textureUniformStep_.x " << Step[0] - << " textureUniformStep_.y " << Step[1] - << " textureUniformStrideFactor_ " << Stride - << " textureUniformProjMatrix_ " << textureUniformProjMatrix_; - - GLfloat ccm[9] = { - params.combinedMatrix[0][0], - params.combinedMatrix[0][1], - params.combinedMatrix[0][2], - params.combinedMatrix[1][0], - params.combinedMatrix[1][1], - params.combinedMatrix[1][2], - params.combinedMatrix[2][0], - params.combinedMatrix[2][1], - params.combinedMatrix[2][2], - }; - glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); - LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; - - /* - * 0 = Red, 1 = Green, 2 = Blue - */ - glUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]); - LOG(Debayer, Debug) << " blackLevelUniformDataIn_ " << blackLevelUniformDataIn_ << " data " << params.blackLevel; - - /* - * Gamma - */ - glUniform1f(gammaUniformDataIn_, params.gamma); - LOG(Debayer, Debug) << " gammaUniformDataIn_ " << gammaUniformDataIn_ << " data " << params.gamma; - - /* - * Contrast - */ - glUniform1f(contrastExpUniformDataIn_, params.contrastExp); - LOG(Debayer, Debug) << " contrastExpUniformDataIn_ " << contrastExpUniformDataIn_ << " data " << params.contrastExp; - - return; -} - int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer) { bool dmabuf_import_succeeded = false; + int pipelineResult = 0; /* eGL context switch */ egl_.makeCurrent(); @@ -540,20 +251,17 @@ int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output, /* Generate the output render framebuffer as render to texture */ egl_.createOutputDMABufTexture2D(*eglImageRGBAOut_, output->planes()[0].fd.get()); - setShaderVariableValues(params); - glViewport(0, 0, width_, height_); - glClear(GL_COLOR_BUFFER_BIT); - glDrawArrays(GL_TRIANGLE_FAN, 0, DEBAYER_OPENGL_COORDS); + pipelineResult = gpuIspShaderPassDemosiac_.process(*eglImageBayerIn_, *eglImageRGBAOut_, width_, height_, params); GLenum err = glGetError(); if (err != GL_NO_ERROR) { LOG(eGL, Error) << "Drawing scene fail " << err; - return -ENODEV; + pipelineResult = -ENODEV; } else { egl_.flushOutput(); } - return 0; + return pipelineResult; } void SoftwareIspPipelineGpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms) @@ -623,7 +331,7 @@ int SoftwareIspPipelineGpu::start() return -EINVAL; /* Raw bayer input as texture */ - eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, inputConfig_.stride / bytesPerPixel_, height_, inputConfig_.stride, GL_TEXTURE0, 0); + eglImageBayerIn_ = std::make_unique<eGLImage>(gpuIspShaderPassDemosiac_.glFormat_, inputConfig_.stride / gpuIspShaderPassDemosiac_.getBytesPerPixel(), height_, inputConfig_.stride, GL_TEXTURE0, 0); /* Texture we will render to */ eglImageRGBAOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1); @@ -636,8 +344,7 @@ void SoftwareIspPipelineGpu::stop() eglImageRGBAOut_.reset(); eglImageBayerIn_.reset(); - if (programId_) - glDeleteProgram(programId_); + gpuIspShaderPassDemosiac_.stop(); } SizeRange SoftwareIspPipelineGpu::sizes(PixelFormat inputFormat, const Size &inputSize) diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.h b/src/libcamera/software_isp/software_isp_pipeline_gpu.h index f0515d889..6a9df2f04 100644 --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.h +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.h @@ -23,16 +23,12 @@ #include "libcamera/internal/software_isp/benchmark.h" #include "libcamera/internal/software_isp/swstats_cpu.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES3/gl32.h> - #include "software_isp_pipeline.h" +#include "gpu_pipeline_shader_pass_demosiac.h" namespace libcamera { #define DEBAYER_EGL_MIN_SIMPLE_RGB_GAIN_TEXTURE_UNITS 4 -#define DEBAYER_OPENGL_COORDS 4 class CameraManager; @@ -68,48 +64,17 @@ private: int processGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer); void configureTexture(GLuint &texture); - /* Shader program identifiers */ - GLuint vertexShaderId_ = 0; - GLuint fragmentShaderId_ = 0; - GLuint programId_ = 0; - /* Pointer to object representing input texture */ std::unique_ptr<eGLImage> eglImageBayerIn_; std::unique_ptr<eGLImage> eglImageRGBAOut_; - /* Shader parameters */ - float firstRed_x_; - float firstRed_y_; - GLint attributeVertex_; - GLint attributeTexture_; - GLint textureUniformStep_; - GLint textureUniformSize_; - GLint textureUniformStrideFactor_; - GLint textureUniformBayerFirstRed_; - GLint textureUniformProjMatrix_; - - GLint textureUniformBayerDataIn_; - - /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ - GLint ccmUniformDataIn_; - - /* Black Level compensation */ - GLint blackLevelUniformDataIn_; - - /* Gamma */ - GLint gammaUniformDataIn_; - - /* Contrast */ - GLint contrastExpUniformDataIn_; - Rectangle window_; std::unique_ptr<SwStatsCpu> stats_; eGL egl_; uint32_t width_; uint32_t height_; - GLint glFormat_; - unsigned int bytesPerPixel_; - uint32_t shaderStridePixels_; + + GpuIspShaderPassDemosiac gpuIspShaderPassDemosiac_; }; } /* namespace libcamera */
Switch to using GpuIspShaderPassDemosiac as the first instance of our multi-pass GPUISP implementation. Subsequent patches will move elements of this leviathan into discreet elements with an objective of eliminating register spill, separation of concerns and de-spaghettification. Code red patches are always best. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> --- src/libcamera/egl.cpp | 6 +- .../software_isp_pipeline_gpu.cpp | 325 +----------------- .../software_isp/software_isp_pipeline_gpu.h | 41 +-- 3 files changed, 20 insertions(+), 352 deletions(-)