]> git.lizzy.rs Git - minetest.git/blob - src/client/render/secondstage.cpp
Clear exposure compensation state textures on creation (#13151)
[minetest.git] / src / client / render / secondstage.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2017 numzero, Lobachevskiy Vitaliy <numzer0@yandex.ru>
5 Copyright (C) 2020 appgurueu, Lars Mueller <appgurulars@gmx.de>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "secondstage.h"
23 #include "client/client.h"
24 #include "client/shader.h"
25 #include "client/tile.h"
26
27 PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_texture_map) :
28         shader_id(_shader_id), texture_map(_texture_map)
29 {
30         assert(texture_map.size() <= video::MATERIAL_MAX_TEXTURES);
31         configureMaterial();
32 }
33
34 void PostProcessingStep::configureMaterial()
35 {
36         material.UseMipMaps = false;
37         material.ZBuffer = true;
38         material.ZWriteEnable = video::EZW_ON;
39         for (u32 k = 0; k < texture_map.size(); ++k) {
40                 material.TextureLayer[k].AnisotropicFilter = false;
41                 material.TextureLayer[k].BilinearFilter = false;
42                 material.TextureLayer[k].TrilinearFilter = false;
43                 material.TextureLayer[k].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
44                 material.TextureLayer[k].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
45         }
46 }
47
48 void PostProcessingStep::setRenderSource(RenderSource *_source)
49 {
50         source = _source;
51 }
52
53 void PostProcessingStep::setRenderTarget(RenderTarget *_target)
54 {
55         target = _target;
56 }
57
58 void PostProcessingStep::reset(PipelineContext &context)
59 {
60 }
61
62 void PostProcessingStep::run(PipelineContext &context)
63 {
64         if (target)
65                 target->activate(context);
66
67         // attach the shader
68         material.MaterialType = context.client->getShaderSource()->getShaderInfo(shader_id).material;
69
70         auto driver = context.device->getVideoDriver();
71
72         for (u32 i = 0; i < texture_map.size(); i++)
73                 material.TextureLayer[i].Texture = source->getTexture(texture_map[i]);
74
75         static const video::SColor color = video::SColor(0, 0, 0, 255);
76         static const video::S3DVertex vertices[4] = {
77                         video::S3DVertex(1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
78                                         color, 1.0, 0.0),
79                         video::S3DVertex(-1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
80                                         color, 0.0, 0.0),
81                         video::S3DVertex(-1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
82                                         color, 0.0, 1.0),
83                         video::S3DVertex(1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
84                                         color, 1.0, 1.0),
85         };
86         static const u16 indices[6] = {0, 1, 2, 2, 3, 0};
87         driver->setMaterial(material);
88         driver->drawVertexPrimitiveList(&vertices, 4, &indices, 2);
89 }
90
91 void PostProcessingStep::setBilinearFilter(u8 index, bool value)
92 {
93         assert(index < video::MATERIAL_MAX_TEXTURES);
94         material.TextureLayer[index].BilinearFilter = value;
95 }
96
97 RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client)
98 {
99         auto buffer = pipeline->createOwned<TextureBuffer>();
100         auto driver = client->getSceneManager()->getVideoDriver();
101
102         // configure texture formats
103         video::ECOLOR_FORMAT color_format = video::ECF_A8R8G8B8;
104         if (driver->queryTextureFormat(video::ECF_A16B16G16R16F))
105                 color_format = video::ECF_A16B16G16R16F;
106
107         video::ECOLOR_FORMAT depth_format = video::ECF_D16; // fallback depth format
108         if (driver->queryTextureFormat(video::ECF_D32))
109                 depth_format = video::ECF_D32;
110         else if (driver->queryTextureFormat(video::ECF_D24S8))
111                 depth_format = video::ECF_D24S8;
112
113
114         // init post-processing buffer
115         static const u8 TEXTURE_COLOR = 0;
116         static const u8 TEXTURE_DEPTH = 1;
117         static const u8 TEXTURE_BLOOM = 2;
118         static const u8 TEXTURE_EXPOSURE_1 = 3;
119         static const u8 TEXTURE_EXPOSURE_2 = 4;
120         static const u8 TEXTURE_BLOOM_DOWN = 10;
121         static const u8 TEXTURE_BLOOM_UP = 20;
122
123         buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format);
124         buffer->setTexture(TEXTURE_EXPOSURE_1, core::dimension2du(1,1), "exposure_1", color_format, /*clear:*/ true);
125         buffer->setTexture(TEXTURE_EXPOSURE_2, core::dimension2du(1,1), "exposure_2", color_format, /*clear:*/ true);
126         buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format);
127
128         // attach buffer to the previous step
129         previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH));
130
131         // shared variables
132         u32 shader_id;
133
134         // Number of mipmap levels of the bloom downsampling texture
135         const u8 MIPMAP_LEVELS = 4;
136
137         const bool enable_bloom = g_settings->getBool("enable_bloom");
138         const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure");
139
140         // post-processing stage
141
142         u8 source = TEXTURE_COLOR;
143
144         // common downsampling step for bloom or autoexposure
145         if (enable_bloom || enable_auto_exposure) {
146
147                 v2f downscale = scale * 0.5;
148                 for (u8 i = 0; i < MIPMAP_LEVELS; i++) {
149                         buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("downsample") + std::to_string(i), color_format);
150                         if (enable_bloom)
151                                 buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("upsample") + std::to_string(i), color_format);
152                         downscale *= 0.5;
153                 }
154
155                 if (enable_bloom) {
156                         buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format);
157
158                         // get bright spots
159                         u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH);
160                         RenderStep *extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_EXPOSURE_1 });
161                         extract_bloom->setRenderSource(buffer);
162                         extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM));
163                         source = TEXTURE_BLOOM;
164                 }
165
166                 // downsample
167                 shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH);
168                 for (u8 i = 0; i < MIPMAP_LEVELS; i++) {
169                         auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source });
170                         step->setRenderSource(buffer);
171                         step->setBilinearFilter(0, true);
172                         step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM_DOWN + i));
173                         source = TEXTURE_BLOOM_DOWN + i;
174                 }
175         }
176
177         if (enable_bloom) {
178                 // upsample
179                 shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH);
180                 for (u8 i = MIPMAP_LEVELS - 1; i > 0; i--) {
181                         auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { u8(TEXTURE_BLOOM_DOWN + i - 1), source });
182                         step->setRenderSource(buffer);
183                         step->setBilinearFilter(0, true);
184                         step->setBilinearFilter(1, true);
185                         step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, u8(TEXTURE_BLOOM_UP + i - 1)));
186                         source = TEXTURE_BLOOM_UP + i - 1;
187                 }
188         }
189
190         if (enable_auto_exposure) {
191                 shader_id = client->getShaderSource()->getShader("update_exposure", TILE_MATERIAL_PLAIN, NDT_MESH);
192                 auto update_exposure = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_EXPOSURE_1, u8(TEXTURE_BLOOM_DOWN + MIPMAP_LEVELS - 1) });
193                 update_exposure->setBilinearFilter(1, true);
194                 update_exposure->setRenderSource(buffer);
195                 update_exposure->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_EXPOSURE_2));
196         }
197
198         // final post-processing
199         shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH);
200         PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM_UP, TEXTURE_EXPOSURE_2 });
201         pipeline->addStep(effect);
202         effect->setBilinearFilter(1, true); // apply filter to the bloom
203         effect->setRenderSource(buffer);
204
205         if (enable_auto_exposure) {
206                 pipeline->addStep<SwapTexturesStep>(buffer, TEXTURE_EXPOSURE_1, TEXTURE_EXPOSURE_2);
207         }
208
209         return effect;
210 }