From 4811e4263216a2f282cfe146e247578b50005e42 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Thu, 8 Aug 2024 11:04:35 -0700 Subject: (WIP) Local paintmap modification test --- indra/newview/llterrainpaintmap.cpp | 118 +++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 8ccde74c93..6979464cd3 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -38,18 +38,31 @@ #include "llsurface.h" #include "llsurfacepatch.h" #include "llviewercamera.h" +#include "llviewercontrol.h" #include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewertexture.h" -// static -bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +namespace +{ +#ifdef SHOW_ASSERT +void check_tex(const LLViewerTexture& tex) { llassert(tex.getComponents() == 3); llassert(tex.getWidth() > 0 && tex.getHeight() > 0); llassert(tex.getWidth() == tex.getHeight()); llassert(tex.getPrimaryFormat() == GL_RGB); llassert(tex.getGLTexture()); +} +#endif +} // namespace + +// static +bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif const LLSurface& surface = region.getLand(); const U32 patch_count = surface.getPatchesPerEdge(); @@ -283,3 +296,104 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& return success; } + +// TODO: Decide when to apply the paint queue - ideally once per frame per region +// Applies paints and then clears the paint queue +// *NOTE The paint queue is also cleared when setting the paintmap texture +void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue) +{ + if (queue.empty()) { return; } + +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + + gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); + + const std::vector& queue_list = queue.get(); + for (size_t i = 0; i < queue_list.size(); ++i) + { + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + queue.convertBitDepths(i, 8); + const LLTerrainPaint::ptr_t& paint = queue_list[i]; + + if (paint->mData.empty()) { continue; } + constexpr GLint level = 0; + if ((paint->mStartX >= tex.getWidth() - 1) || (paint->mStartY >= tex.getHeight() - 1)) { continue; } + constexpr GLint miplevel = 0; + const S32 x_offset = paint->mStartX; + const S32 y_offset = paint->mStartY; + const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset); + const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset); + const U8* pixels = paint->mData.data(); + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels); + stop_glerror(); + } + + // Generating mipmaps at the end... + glGenerateMipmap(GL_TEXTURE_2D); + stop_glerror(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + queue.clear(); +} + +bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) +{ + llassert(paint); + if (!paint) { return false; } + + // The paint struct should be pre-validated before this code is reached. + llassert(!paint->mData.empty()); + // The internal paint map image is currently 8 bits, so that's the maximum + // allowed bit depth. + llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8); + llassert(paint->mData.size() == (LLTerrainPaint::COMPONENTS * paint->mWidthX * paint->mWidthY)); + llassert(paint->mWidthX > 0); + llassert(paint->mWidthY > 0); +#ifdef SHOW_ASSERT + static LLCachedControl max_texture_width(gSavedSettings, "RenderMaxTextureResolution", 2048); +#endif + llassert(paint->mWidthX <= max_texture_width); + llassert(paint->mWidthY <= max_texture_width); + llassert(paint->mStartX < max_texture_width); + llassert(paint->mStartY < max_texture_width); + + mList.push_back(paint); + return true; +} + +bool LLTerrainPaintQueue::empty() const +{ + return mList.empty(); +} + +void LLTerrainPaintQueue::clear() +{ + mList.clear(); +} + +void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) +{ + llassert(target_bit_depth > 0 && target_bit_depth <= 8); + llassert(index < mList.size()); + + LLTerrainPaint::ptr_t& paint = mList[index]; + if (paint->mBitDepth == target_bit_depth) { return; } + + const F32 old_bit_max = F32((1 << paint->mBitDepth) - 1); + const F32 new_bit_max = F32((1 << target_bit_depth) - 1); + const F32 bit_conversion_factor = new_bit_max / old_bit_max; + + for (U8& color : paint->mData) + { + color = (U8)llround(F32(color) * bit_conversion_factor); + } + + paint->mBitDepth = target_bit_depth; +} -- cgit v1.2.3 From f1d892ecd1383ce2d774a2dcf92209951f79f63e Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 9 Aug 2024 17:23:43 -0700 Subject: secondlife/viewer#1883: (WIP) Alpha paint queue --- indra/newview/llterrainpaintmap.cpp | 326 +++++++++++++++++++++++++++++++++++- 1 file changed, 317 insertions(+), 9 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 6979464cd3..7dc09a4748 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -31,6 +31,8 @@ // library includes #include "llglslshader.h" #include "llrendertarget.h" +#include "llrender2dutils.h" +#include "llshadermgr.h" #include "llvertexbuffer.h" // newview includes @@ -89,8 +91,8 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& // Bind the debug shader and render terrain to tex // Use a scratch render target because its dimensions may exceed the standard bake target, and this is a one-off bake LLRenderTarget scratch_target; - const S32 dim = llmin(tex.getWidth(), tex.getHeight()); - scratch_target.allocate(dim, dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, LLTexUnit::eTextureMipGeneration::TMG_NONE); if (!scratch_target.isComplete()) { @@ -117,6 +119,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& const F32 region_half_width = region_width / 2.0f; const F32 region_camera_height = surface.getMaxZ() + DEFAULT_NEAR_PLANE; LLViewerCamera camera; + // TODO: Huh... I just realized this view vector is not completely vertical const LLVector3 region_center = LLVector3(region_half_width, region_half_width, 0.0) + region.getOriginAgent(); const LLVector3 camera_origin = LLVector3(0.0f, 0.0f, region_camera_height) + region_center; camera.lookAt(camera_origin, region_center, LLVector3::y_axis); @@ -250,6 +253,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& S32 alpha_ramp = shader.enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); LLPointer alpha_ramp_texture = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD_2D); + // TODO: Consider using LLGLSLShader::bindTexture gGL.getTexUnit(alpha_ramp)->bind(alpha_ramp_texture); gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -263,6 +267,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& const U32 vertex_offset = n * patch_index; llassert(index_offset + ni <= region_indices); llassert(vertex_offset + n <= region_vertices); + // TODO: Try a single big drawRange and see if that still works buf->drawRange(LLRender::TRIANGLES, vertex_offset, vertex_offset + n - 1, ni, index_offset); } } @@ -282,7 +287,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& gGL.flush(); LLVertexBuffer::unbind(); // Final step: Copy the output to the terrain paintmap - const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, dim, dim); + const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, tex.getWidth(), tex.getHeight()); if (!success) { LL_WARNS() << "Failed to copy framebuffer to paintmap" << LL_ENDL; @@ -297,10 +302,10 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& return success; } -// TODO: Decide when to apply the paint queue - ideally once per frame per region +// *TODO: Decide when to apply the paint queue - ideally once per frame per region // Applies paints and then clears the paint queue // *NOTE The paint queue is also cleared when setting the paintmap texture -void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue) +void LLTerrainPaintMap::applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue) { if (queue.empty()) { return; } @@ -310,6 +315,11 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); + // glTexSubImage2D replaces all pixels in the rectangular region. That + // makes it unsuitable for alpha. + llassert(queue.getComponents() == LLTerrainPaint::RGB); + constexpr GLenum pixformat = GL_RGB; + const std::vector& queue_list = queue.get(); for (size_t i = 0; i < queue_list.size(); ++i) { @@ -328,8 +338,10 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset); const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset); const U8* pixels = paint->mData.data(); - constexpr GLenum pixformat = GL_RGB; constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + // *TODO: Performance suggestion: Use the sub-image utility function + // that LLImageGL::setSubImage uses to split texture updates into + // lines, if that's faster. glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels); stop_glerror(); } @@ -343,7 +355,284 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu queue.clear(); } -bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) +namespace +{ + +// A general-purpose vertex buffer of a quad for stamping textures on the z=0 +// plane. +// *NOTE: Because we know the vertex XY coordinates go from 0 to 1 +// pre-transform, UVs can be calculated from the vertices +LLVertexBuffer& get_paint_triangle_buffer() +{ + static LLPointer buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); + static bool initialized = false; + if (!initialized) + { + // Two triangles forming a square from (0,0) to (1,1) + buf->allocateBuffer(/*vertices =*/ 4, /*indices =*/ 6); + LLStrider indices; + LLStrider vertices; + buf->getVertexStrider(vertices); + buf->getIndexStrider(indices); + // y + // 2....3 + // ^ . . + // | 0....1 + // | + // -------> x + // + // triangle 1: 0,1,2 + // triangle 2: 1,3,2 + (*(vertices++)).set(0.0f, 0.0f, 0.0f); + (*(vertices++)).set(1.0f, 0.0f, 0.0f); + (*(vertices++)).set(0.0f, 1.0f, 0.0f); + (*(vertices++)).set(1.0f, 1.0f, 0.0f); + *(indices++) = 0; + *(indices++) = 1; + *(indices++) = 2; + *(indices++) = 1; + *(indices++) = 3; + *(indices++) = 2; + buf->unmapBuffer(); + } + return *buf; +} + +}; + +// static +LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + llassert(queue_in.getComponents() == LLTerrainPaint::RGBA); + + // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead + // TODO: even if it means performing extra render operations to apply the paints, in rare cases where the paints can't all fit within an area that can be represented by the buffer + LLRenderTarget scratch_target; + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + LLTexUnit::eTextureMipGeneration::TMG_NONE); + if (!scratch_target.isComplete()) + { + llassert(false); + LL_WARNS() << "Failed to allocate render target" << LL_ENDL; + return false; + } + gGL.getTexUnit(0)->disable(); + stop_glerror(); + + scratch_target.bindTarget(); + glClearColor(0, 0, 0, 0); + scratch_target.clear(); + const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; + const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; + + LLVertexBuffer* buf = &get_paint_triangle_buffer(); + + // Update projection matrix and viewport + // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. + { + stop_glerror(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f); + stop_glerror(); + const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0); + glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight()); + } + + // View matrix + // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. + // Camera is centered in the middle of the framebuffer. + glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + { + LLViewerCamera camera; + const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); + const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f); + camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis); + camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); + GLfloat ogl_matrix[16]; + camera.getOpenGLTransform(ogl_matrix); + view *= glh::matrix4f(ogl_matrix); + } + + LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable scissor(GL_SCISSOR_TEST); + LLGLEnable cull_face(GL_CULL_FACE); + LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + LLGLSLShader& shader = gTerrainStampProgram; + shader.bind(); + + // First, apply the paint map as the background + { + glh::matrix4f model; + { + model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); + // We care about the whole paintmap, which is already a power of two. + // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0) + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB); + + // Incrementally apply each RGBA paint to the render target, then extract + // the result back into memory as an RGB paint. + // Put each result in queue_out. + const std::vector& queue_in_list = queue_in.get(); + for (size_t i = 0; i < queue_in_list.size(); ++i) + { + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for paint operations (this + // could change in the future). + queue_in.convertBitDepths(i, 8); + const LLTerrainPaint::ptr_t& paint_in = queue_in_list[i]; + + // Modelview matrix for the current paint + // View matrix is already computed. Just need the model matrix. + // Orthographic projection matrix is already updated + glh::matrix4f model; + { + model.set_scale(glh::vec3f(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); + model.set_translate(glh::vec3f(paint_in->mStartX, paint_in->mStartY, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + // Generate temporary stamp texture from paint contents. + // Our stamp image needs to be a power of two. + // Because the paint data may not cover a whole power-of-two region, + // allocate a bigger 2x2 image if needed, but set the image data later + // for a subset of the image. + // Pixel data outside this subset is left undefined. We will use + // TERRAIN_STAMP_SCALE in the stamp shader to define the subset of the + // image we care about. + const U32 width_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthX)))); + const U32 height_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthY)))); + LLPointer stamp_image; + { + // Create image object (dimensions not yet initialized in GL) + U32 stamp_tex_name; + LLImageGL::generateTextures(1, &stamp_tex_name); + const U32 components = paint_in->mComponents; + constexpr LLGLenum target = GL_TEXTURE_2D; + const LLGLenum internal_format = paint_in->mComponents == 4 ? GL_RGBA8 : GL_RGB8; + const LLGLenum format = paint_in->mComponents == 4 ? GL_RGBA : GL_RGB; + constexpr LLGLenum type = GL_UNSIGNED_BYTE; + stamp_image = new LLImageGL(stamp_tex_name, components, target, internal_format, format, type, LLTexUnit::TAM_WRAP); + // Nearest-neighbor filtering to reduce surprises + stamp_image->setFilteringOption(LLTexUnit::TFO_POINT); + + // Initialize the image dimensions in GL + constexpr U8* undefined_data_for_now = nullptr; + gGL.getTexUnit(0)->bind(stamp_image, false, true); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_rounded, height_rounded, 0, format, type, undefined_data_for_now); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + stamp_image->setSize(width_rounded, height_rounded, components); + stamp_image->setDiscardLevel(0); + + // Manually set a subset of the image in GL + const U8* data = paint_in->mData.data(); + const S32 data_width = paint_in->mWidthX; + const S32 data_height = paint_in->mWidthY; + constexpr S32 origin = 0; + // width = data_width; height = data_height. i.e.: Copy the full + // contents of data into the image. + stamp_image->setSubImage(data, data_width, data_height, origin, origin, /*width=*/data_width, /*height=*/data_height); + } + + // Apply ("stamp") the paint to the render target + { + shader.bindTextureImageGL(LLShaderMgr::DIFFUSE_MAP, stamp_image); + const F32 width_fraction = F32(paint_in->mWidthX) / F32(width_rounded); + const F32 height_fraction = F32(paint_in->mWidthY) / F32(height_rounded); + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, width_fraction, height_fraction); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + // Extract the result back into memory as an RGB paint + LLTerrainPaint::ptr_t paint_out = std::make_shared(); + { + paint_out->mStartX = paint_in->mStartX; + paint_out->mStartY = paint_in->mStartY; + paint_out->mWidthX = paint_in->mWidthX; + paint_out->mWidthY = paint_in->mWidthY; + paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mComponents = LLTerrainPaint::RGB; + paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); + constexpr GLint miplevel = 0; + const S32 x_offset = paint_out->mStartX; + const S32 y_offset = paint_out->mStartY; + const S32 width = llmin(paint_out->mWidthX, tex.getWidth() - x_offset); + const S32 height = llmin(paint_out->mWidthY, tex.getHeight() - y_offset); + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + llassert(paint_out->mData.size() <= std::numeric_limits::max()); + const GLsizei buf_size = (GLsizei)paint_out->mData.size(); + U8* pixels = paint_out->mData.data(); + glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels); + } + + // Enqueue the result to the new paint queue, with bit depths per color + // channel reduced from 8 to 5, and reduced from RGBA (paintmap + // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle + // update without alpha mask). This format is suitable for sending + // over the network. + // *TODO: At some point, queue_out will pass through a network + // round-trip which will reduce the bit depth, making the + // pre-conversion step not necessary. + queue_out.enqueue(paint_out); + queue_out.convertBitDepths(queue_out.size()-1, 5); + } + + queue_in.clear(); + + scratch_target.flush(); + + LLGLSLShader::unbind(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + return queue_out; +} + +LLTerrainPaintQueue::LLTerrainPaintQueue(U8 components) +: mComponents(components) +{ + llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); +} + +LLTerrainPaintQueue::LLTerrainPaintQueue(const LLTerrainPaintQueue& other) +{ + *this = other; + llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); +} + +LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(const LLTerrainPaintQueue& other) +{ + mComponents = other.mComponents; + mList = other.mList; + return *this; +} + +bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run) { llassert(paint); if (!paint) { return false; } @@ -353,7 +642,7 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) // The internal paint map image is currently 8 bits, so that's the maximum // allowed bit depth. llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8); - llassert(paint->mData.size() == (LLTerrainPaint::COMPONENTS * paint->mWidthX * paint->mWidthY)); + llassert(paint->mData.size() == (mComponents * paint->mWidthX * paint->mWidthY)); llassert(paint->mWidthX > 0); llassert(paint->mWidthY > 0); #ifdef SHOW_ASSERT @@ -364,10 +653,29 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) llassert(paint->mStartX < max_texture_width); llassert(paint->mStartY < max_texture_width); - mList.push_back(paint); + if (!dry_run) { mList.push_back(paint); } return true; } +bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& paint_queue) +{ + constexpr bool dry_run = true; + for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) + { + if (!enqueue(paint), dry_run) { return false; } + } + for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) + { + enqueue(paint); + } + return true; +} + +size_t LLTerrainPaintQueue::size() const +{ + return mList.size(); +} + bool LLTerrainPaintQueue::empty() const { return mList.empty(); -- cgit v1.2.3 From 642ace3c75d08cc55370374f5a091f0c8ff41a4c Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 16 Aug 2024 17:27:57 -0700 Subject: secondlife/viewer#1883: (WIP) (not yet working) Brush queue --- indra/newview/llterrainpaintmap.cpp | 349 ++++++++++++++++++++++++++++++++---- 1 file changed, 315 insertions(+), 34 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 7dc09a4748..6a57605325 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -575,12 +575,16 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur paint_out->mWidthY = paint_in->mWidthY; paint_out->mBitDepth = 8; // Will be reduced to 5 bits later paint_out->mComponents = LLTerrainPaint::RGB; +#ifdef SHOW_ASSERT + paint_out->assert_confined_to(tex); +#endif + paint_out->confine_to(tex); paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); constexpr GLint miplevel = 0; const S32 x_offset = paint_out->mStartX; const S32 y_offset = paint_out->mStartY; - const S32 width = llmin(paint_out->mWidthX, tex.getWidth() - x_offset); - const S32 height = llmin(paint_out->mWidthY, tex.getHeight() - y_offset); + const S32 width = paint_out->mWidthX; + const S32 height = paint_out->mWidthY; constexpr GLenum pixformat = GL_RGB; constexpr GLenum pixtype = GL_UNSIGNED_BYTE; llassert(paint_out->mData.size() <= std::numeric_limits::max()); @@ -613,22 +617,294 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur return queue_out; } +// static +LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + + // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead + // TODO: even if it means performing extra render operations to apply the brushes, in rare cases where the paints can't all fit within an area that can be represented by the buffer + LLRenderTarget scratch_target; + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + LLTexUnit::eTextureMipGeneration::TMG_NONE); + if (!scratch_target.isComplete()) + { + llassert(false); + LL_WARNS() << "Failed to allocate render target" << LL_ENDL; + return false; + } + gGL.getTexUnit(0)->disable(); + stop_glerror(); + + scratch_target.bindTarget(); + glClearColor(0, 0, 0, 0); + scratch_target.clear(); + const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; + const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; + + LLVertexBuffer* buf = &get_paint_triangle_buffer(); + + // Update projection matrix and viewport + // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. + { + stop_glerror(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f); + stop_glerror(); + const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0); + glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight()); + } + + // View matrix + // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. + // Camera is centered in the middle of the framebuffer. + glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + { + LLViewerCamera camera; + const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); + const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f); + camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis); + camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); + GLfloat ogl_matrix[16]; + camera.getOpenGLTransform(ogl_matrix); + view *= glh::matrix4f(ogl_matrix); + } + + LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable scissor(GL_SCISSOR_TEST); + LLGLEnable cull_face(GL_CULL_FACE); + LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + LLGLSLShader& shader = gTerrainStampProgram; + shader.bind(); + + // First, apply the paint map as the background + { + glh::matrix4f model; + { + model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); + // We care about the whole paintmap, which is already a power of two. + // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0) + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB); + + // Incrementally apply each brush stroke to the render target, then extract + // the result back into memory as an RGB paint. + // Put each result in queue_out. + const std::vector& brush_list = queue_in.get(); + for (size_t i = 0; i < brush_list.size(); ++i) + { + const LLTerrainBrush::ptr_t& brush_in = brush_list[i]; + + // Modelview matrix for the current brush + // View matrix is already computed. Just need the model matrix. + // Orthographic projection matrix is already updated + // *NOTE: Brush path information is in region space. It will need to be + // converted to paintmap pixel space before it makes sense. + F32 brush_width_x; + F32 brush_width_y; + F32 brush_start_x; + F32 brush_start_y; + { + F32 min_x = brush_in->mPath[0].mV[VX]; + F32 max_x = min_x; + F32 min_y = brush_in->mPath[0].mV[VY]; + F32 max_y = min_y; + for (size_t i = 1; i < brush_in->mPath.size(); ++i) + { + const F32 x = brush_in->mPath[i].mV[VX]; + const F32 y = brush_in->mPath[i].mV[VY]; + min_x = llmin(min_x, x); + max_x = llmax(max_x, x); + min_y = llmin(min_y, y); + max_y = llmax(max_y, y); + } + brush_width_x = brush_in->mBrushSize + (max_x - min_x); + brush_width_y = brush_in->mBrushSize + (max_y - min_y); + brush_start_x = min_x - (brush_in->mBrushSize / 2.0f); + brush_start_y = min_y - (brush_in->mBrushSize / 2.0f); + // Convert brush path information to paintmap pixel space from region + // space. + brush_width_x *= tex.getWidth() / region.getWidth(); + brush_width_y *= tex.getHeight() / region.getWidth(); + brush_start_x *= tex.getWidth() / region.getWidth(); + brush_start_y *= tex.getHeight() / region.getWidth(); + } + glh::matrix4f model; + { + model.set_scale(glh::vec3f(brush_width_x, brush_width_y, 1.0f)); + model.set_translate(glh::vec3f(brush_start_x, brush_start_y, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + // Apply the "brush" to the render target + { + // TODO: Use different shader for this - currently this is using the stamp shader. The white image is just a placeholder for now + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, LLViewerFetchedTexture::sWhiteImagep); + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + // Extract the result back into memory as an RGB paint + LLTerrainPaint::ptr_t paint_out = std::make_shared(); + { + paint_out->mStartX = U16(floor(brush_start_x)); + paint_out->mStartY = U16(floor(brush_start_y)); + const F32 dX = brush_start_x - F32(paint_out->mStartX); + const F32 dY = brush_start_y - F32(paint_out->mStartY); + paint_out->mWidthX = U16(ceil(brush_width_x + dX)); + paint_out->mWidthY = U16(ceil(brush_width_y + dY)); + paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mComponents = LLTerrainPaint::RGB; + // The brush strokes are expected to sometimes partially venture + // outside of the paintmap bounds. + paint_out->confine_to(tex); + paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); + constexpr GLint miplevel = 0; + const S32 x_offset = paint_out->mStartX; + const S32 y_offset = paint_out->mStartY; + const S32 width = paint_out->mWidthX; + const S32 height = paint_out->mWidthY; + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + llassert(paint_out->mData.size() <= std::numeric_limits::max()); + const GLsizei buf_size = (GLsizei)paint_out->mData.size(); + U8* pixels = paint_out->mData.data(); + glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels); + } + + // Enqueue the result to the new paint queue, with bit depths per color + // channel reduced from 8 to 5, and reduced from RGBA (paintmap + // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle + // update without alpha mask). This format is suitable for sending + // over the network. + // *TODO: At some point, queue_out will pass through a network + // round-trip which will reduce the bit depth, making the + // pre-conversion step not necessary. + queue_out.enqueue(paint_out); + queue_out.convertBitDepths(queue_out.size()-1, 5); + } + + queue_in.clear(); + + scratch_target.flush(); + + LLGLSLShader::unbind(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + return queue_out; +} + +template +LLTerrainQueue::LLTerrainQueue(LLTerrainQueue& other) +{ + *this = other; +} + +template +LLTerrainQueue& LLTerrainQueue::operator=(LLTerrainQueue& other) +{ + mList = other.mList; + return *this; +} + +template +bool LLTerrainQueue::enqueue(std::shared_ptr& t, bool dry_run) +{ + if (!dry_run) { mList.push_back(t); } + return true; +} + +template +bool LLTerrainQueue::enqueue(std::vector>& list) +{ + constexpr bool dry_run = true; + for (T::ptr_t& t : list) + { + if (!enqueue(t), dry_run) { return false; } + } + for (T::ptr_t& t : list) + { + enqueue(t); + } + return true; +} + +template +size_t LLTerrainQueue::size() const +{ + return mList.size(); +} + +template +bool LLTerrainQueue::empty() const +{ + return mList.empty(); +} + +template +void LLTerrainQueue::clear() +{ + mList.clear(); +} + +void LLTerrainPaint::assert_confined_to(const LLTexture& tex) const +{ + llassert(mStartX >= 0 && mStartX < tex.getWidth()); + llassert(mStartY >= 0 && mStartY < tex.getHeight()); + llassert(mWidthX <= tex.getWidth() - mStartX); + llassert(mWidthY <= tex.getHeight() - mStartY); +} + +void LLTerrainPaint::confine_to(const LLTexture& tex) +{ + mStartX = llmax(mStartX, 0); + mStartY = llmax(mStartY, 0); + mWidthX = llmin(mWidthX, tex.getWidth() - mStartX); + mWidthY = llmin(mWidthY, tex.getHeight() - mStartY); + assert_confined_to(tex); +} + LLTerrainPaintQueue::LLTerrainPaintQueue(U8 components) : mComponents(components) { llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); } -LLTerrainPaintQueue::LLTerrainPaintQueue(const LLTerrainPaintQueue& other) +LLTerrainPaintQueue::LLTerrainPaintQueue(LLTerrainPaintQueue& other) +: LLTerrainQueue(other) +, mComponents(other.mComponents) { - *this = other; llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); } -LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(const LLTerrainPaintQueue& other) +LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(LLTerrainPaintQueue& other) { + LLTerrainQueue::operator=(other); mComponents = other.mComponents; - mList = other.mList; return *this; } @@ -653,37 +929,12 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run) llassert(paint->mStartX < max_texture_width); llassert(paint->mStartY < max_texture_width); - if (!dry_run) { mList.push_back(paint); } - return true; + return LLTerrainQueue::enqueue(paint, dry_run); } -bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& paint_queue) +bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& queue) { - constexpr bool dry_run = true; - for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) - { - if (!enqueue(paint), dry_run) { return false; } - } - for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) - { - enqueue(paint); - } - return true; -} - -size_t LLTerrainPaintQueue::size() const -{ - return mList.size(); -} - -bool LLTerrainPaintQueue::empty() const -{ - return mList.empty(); -} - -void LLTerrainPaintQueue::clear() -{ - mList.clear(); + return LLTerrainQueue::enqueue(queue.mList); } void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) @@ -705,3 +956,33 @@ void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) paint->mBitDepth = target_bit_depth; } + +LLTerrainBrushQueue::LLTerrainBrushQueue() +: LLTerrainQueue() +{ +} + +LLTerrainBrushQueue::LLTerrainBrushQueue(LLTerrainBrushQueue& other) +: LLTerrainQueue(other) +{ +} + +LLTerrainBrushQueue& LLTerrainBrushQueue::operator=(LLTerrainBrushQueue& other) +{ + LLTerrainQueue::operator=(other); + return *this; +} + +bool LLTerrainBrushQueue::enqueue(LLTerrainBrush::ptr_t& brush, bool dry_run) +{ + llassert(brush->mBrushSize > 0); + llassert(!brush->mPath.empty()); + llassert(brush->mPathOffset < brush->mPath.size()); + llassert(brush->mPathOffset < 2); // Harmless, but doesn't do anything useful, so might be a sign of implementation error + return LLTerrainQueue::enqueue(brush, dry_run); +} + +bool LLTerrainBrushQueue::enqueue(LLTerrainBrushQueue& queue) +{ + return LLTerrainQueue::enqueue(queue.mList); +} -- cgit v1.2.3 From 81cc4fa7d61e838413b912a4ed2d957cc65bcb46 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 14:30:29 -0700 Subject: secondlife/viewer#1883: (WIP/Alpha/WOMM) Fix some compiler and runtime errors --- indra/newview/llterrainpaintmap.cpp | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 6a57605325..d36e4ea657 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -447,7 +447,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // View matrix // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. // Camera is centered in the middle of the framebuffer. - glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + glm::mat4 view(glm::make_mat4((GLfloat*) OGL_TO_CFR_ROTATION)); { LLViewerCamera camera; const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); @@ -456,7 +456,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); GLfloat ogl_matrix[16]; camera.getOpenGLTransform(ogl_matrix); - view *= glh::matrix4f(ogl_matrix); + view *= glm::make_mat4(ogl_matrix); } LLGLDisable stencil(GL_STENCIL_TEST); @@ -471,14 +471,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // First, apply the paint map as the background { - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); - model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); // We care about the whole paintmap, which is already a power of two. @@ -505,14 +505,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // Modelview matrix for the current paint // View matrix is already computed. Just need the model matrix. // Orthographic projection matrix is already updated - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); - model.set_translate(glh::vec3f(paint_in->mStartX, paint_in->mStartY, 0.0f)); + model = glm::scale(model, glm::vec3(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); + model = glm::translate(model, glm::vec3(paint_in->mStartX, paint_in->mStartY, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); // Generate temporary stamp texture from paint contents. // Our stamp image needs to be a power of two. @@ -663,7 +663,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // View matrix // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. // Camera is centered in the middle of the framebuffer. - glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + glm::mat4 view(glm::make_mat4((GLfloat*)OGL_TO_CFR_ROTATION)); { LLViewerCamera camera; const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); @@ -672,7 +672,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); GLfloat ogl_matrix[16]; camera.getOpenGLTransform(ogl_matrix); - view *= glh::matrix4f(ogl_matrix); + view *= glm::make_mat4(ogl_matrix); } LLGLDisable stencil(GL_STENCIL_TEST); @@ -687,14 +687,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // First, apply the paint map as the background { - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); - model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); // We care about the whole paintmap, which is already a power of two. @@ -748,14 +748,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe brush_start_x *= tex.getWidth() / region.getWidth(); brush_start_y *= tex.getHeight() / region.getWidth(); } - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f(brush_width_x, brush_width_y, 1.0f)); - model.set_translate(glh::vec3f(brush_start_x, brush_start_y, 0.0f)); + model = glm::scale(model, glm::vec3(brush_width_x, brush_width_y, 1.0f)); + model = glm::translate(model, glm::vec3(brush_start_x, brush_start_y, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); // Apply the "brush" to the render target { @@ -842,11 +842,11 @@ template bool LLTerrainQueue::enqueue(std::vector>& list) { constexpr bool dry_run = true; - for (T::ptr_t& t : list) + for (auto& t : list) { if (!enqueue(t), dry_run) { return false; } } - for (T::ptr_t& t : list) + for (auto& t : list) { enqueue(t); } -- cgit v1.2.3 From 303bf1977b802f5a091bec66b65dfb6c2f29b761 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 14:50:27 -0700 Subject: secondlife/viewer#1883: Fix terrain paintmap bit depth hardcoded in places and increase default bit depth to 8 --- indra/newview/llterrainpaintmap.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index d36e4ea657..ec40f299a4 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -573,7 +573,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur paint_out->mStartY = paint_in->mStartY; paint_out->mWidthX = paint_in->mWidthX; paint_out->mWidthY = paint_in->mWidthY; - paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later paint_out->mComponents = LLTerrainPaint::RGB; #ifdef SHOW_ASSERT paint_out->assert_confined_to(tex); @@ -602,7 +602,8 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // round-trip which will reduce the bit depth, making the // pre-conversion step not necessary. queue_out.enqueue(paint_out); - queue_out.convertBitDepths(queue_out.size()-1, 5); + LLCachedControl bit_depth(gSavedSettings, "TerrainPaintBitDepth"); + queue_out.convertBitDepths(queue_out.size()-1, bit_depth); } queue_in.clear(); @@ -775,7 +776,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe const F32 dY = brush_start_y - F32(paint_out->mStartY); paint_out->mWidthX = U16(ceil(brush_width_x + dX)); paint_out->mWidthY = U16(ceil(brush_width_y + dY)); - paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later paint_out->mComponents = LLTerrainPaint::RGB; // The brush strokes are expected to sometimes partially venture // outside of the paintmap bounds. @@ -803,7 +804,8 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // round-trip which will reduce the bit depth, making the // pre-conversion step not necessary. queue_out.enqueue(paint_out); - queue_out.convertBitDepths(queue_out.size()-1, 5); + LLCachedControl bit_depth(gSavedSettings, "TerrainPaintBitDepth"); + queue_out.convertBitDepths(queue_out.size()-1, bit_depth); } queue_in.clear(); -- cgit v1.2.3 From d505eb4fce23e573c5155d1a9ba2857f549ca281 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 15:57:50 -0700 Subject: secondlife/viewer#1883: Fix logic error caught by clang --- indra/newview/llterrainpaintmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index ec40f299a4..09caba8faa 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -846,7 +846,7 @@ bool LLTerrainQueue::enqueue(std::vector>& list) constexpr bool dry_run = true; for (auto& t : list) { - if (!enqueue(t), dry_run) { return false; } + if (!enqueue(t, dry_run)) { return false; } } for (auto& t : list) { -- cgit v1.2.3 From f88401c97a892ea4a6fce13ee15dad1bb976d992 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 11 Oct 2024 09:54:47 -0700 Subject: secondlife/viewer#1883: Review feedback --- indra/newview/llterrainpaintmap.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 09caba8faa..52376e3bf0 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -56,15 +56,15 @@ void check_tex(const LLViewerTexture& tex) llassert(tex.getPrimaryFormat() == GL_RGB); llassert(tex.getGLTexture()); } +#else +#define check_tex(tex) #endif } // namespace // static bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif const LLSurface& surface = region.getLand(); const U32 patch_count = surface.getPatchesPerEdge(); @@ -309,9 +309,7 @@ void LLTerrainPaintMap::applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQ { if (queue.empty()) { return; } -#ifdef SHOW_ASSERT check_tex(tex); -#endif gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); @@ -362,7 +360,7 @@ namespace // plane. // *NOTE: Because we know the vertex XY coordinates go from 0 to 1 // pre-transform, UVs can be calculated from the vertices -LLVertexBuffer& get_paint_triangle_buffer() +LLVertexBuffer* get_paint_triangle_buffer() { static LLPointer buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); static bool initialized = false; @@ -395,7 +393,7 @@ LLVertexBuffer& get_paint_triangle_buffer() *(indices++) = 2; buf->unmapBuffer(); } - return *buf; + return buf.get(); } }; @@ -403,9 +401,7 @@ LLVertexBuffer& get_paint_triangle_buffer() // static LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif llassert(queue_in.getComponents() == LLTerrainPaint::RGBA); // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead @@ -429,7 +425,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; - LLVertexBuffer* buf = &get_paint_triangle_buffer(); + LLVertexBuffer* buf = get_paint_triangle_buffer(); // Update projection matrix and viewport // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. @@ -621,9 +617,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // static LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead // TODO: even if it means performing extra render operations to apply the brushes, in rare cases where the paints can't all fit within an area that can be represented by the buffer @@ -646,7 +640,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; - LLVertexBuffer* buf = &get_paint_triangle_buffer(); + LLVertexBuffer* buf = get_paint_triangle_buffer(); // Update projection matrix and viewport // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. -- cgit v1.2.3 From 07e33dfac78b170d235069fd035771016d3e0403 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 11 Oct 2024 11:50:28 -0700 Subject: secondlife/viewer#1883: Fix compiler errors --- indra/newview/llterrainpaintmap.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llterrainpaintmap.cpp') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 52376e3bf0..a858f92d8e 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -982,3 +982,6 @@ bool LLTerrainBrushQueue::enqueue(LLTerrainBrushQueue& queue) { return LLTerrainQueue::enqueue(queue.mList); } + +template class LLTerrainQueue; +template class LLTerrainQueue; -- cgit v1.2.3