DOSBox-X
|
00001 #include <stdlib.h> 00002 #include <assert.h> 00003 #include <math.h> 00004 00005 #include "dosbox.h" 00006 #include "sdlmain.h" 00007 00008 using namespace std; 00009 00010 #if C_XBRZ 00011 00012 struct SDL_xBRZ sdl_xbrz; 00013 00014 void xBRZ_Initialize() 00015 { 00016 Section_prop* section = static_cast<Section_prop *>(control->GetSection("render")); 00017 00018 LOG(LOG_MISC, LOG_DEBUG)("Early init (renderer): xBRZ options"); 00019 00020 // set some defaults 00021 sdl_xbrz.task_granularity = 16; 00022 sdl_xbrz.max_scale_factor = xbrz::SCALE_FACTOR_MAX; 00023 00024 // read options related to xBRZ here 00025 Prop_multival* prop = section->Get_multival("scaler"); 00026 std::string scaler = prop->GetSection()->Get_string("type"); 00027 sdl_xbrz.enable = ((scaler == "xbrz") || (scaler == "xbrz_bilinear")); 00028 sdl_xbrz.postscale_bilinear = (scaler == "xbrz_bilinear"); 00029 xBRZ_Change_Options(section); 00030 } 00031 00032 void xBRZ_Change_Options(Section_prop* section) 00033 { 00034 sdl_xbrz.task_granularity = section->Get_int("xbrz slice"); 00035 sdl_xbrz.fixed_scale_factor = section->Get_int("xbrz fixed scale factor"); 00036 sdl_xbrz.max_scale_factor = section->Get_int("xbrz max scale factor"); 00037 if ((sdl_xbrz.max_scale_factor < 2) || (sdl_xbrz.max_scale_factor > xbrz::SCALE_FACTOR_MAX)) 00038 sdl_xbrz.max_scale_factor = xbrz::SCALE_FACTOR_MAX; 00039 if ((sdl_xbrz.fixed_scale_factor < 2) || (sdl_xbrz.fixed_scale_factor > xbrz::SCALE_FACTOR_MAX)) 00040 sdl_xbrz.fixed_scale_factor = 0; 00041 } 00042 00043 // returns true if scaling possible/enabled, false otherwise 00044 bool xBRZ_SetScaleParameters(int srcWidth, int srcHeight, int dstWidth, int dstHeight) 00045 { 00046 sdl_xbrz.scale_factor = (sdl_xbrz.fixed_scale_factor == 0) ? 00047 static_cast<int>(std::sqrt((double)dstWidth * dstHeight / (srcWidth * srcHeight)) + 0.5) : 00048 sdl_xbrz.fixed_scale_factor; 00049 00050 // enable minimal scaling if upscale is still possible but requires post-downscale 00051 // having aspect ratio correction on always implies enabled scaler because it gives better quality than DOSBox own method 00052 if (sdl_xbrz.scale_factor == 1 && (render.aspect || dstWidth > srcWidth || dstHeight > srcHeight)) 00053 sdl_xbrz.scale_factor = 2; 00054 00055 if (sdl_xbrz.scale_factor >= 2) 00056 { 00057 // ok to scale, now clamp scale factor if corresponding max option is set 00058 sdl_xbrz.scale_factor = min(sdl_xbrz.scale_factor, sdl_xbrz.max_scale_factor); 00059 sdl_xbrz.scale_on = true; 00060 } 00061 else 00062 { 00063 // scaling impossible 00064 sdl_xbrz.scale_on = false; 00065 } 00066 00067 return sdl_xbrz.scale_on; 00068 } 00069 00070 void xBRZ_Render(const uint32_t* renderBuf, uint32_t* xbrzBuf, const Bit16u *changedLines, const int srcWidth, const int srcHeight, int scalingFactor) 00071 { 00072 #ifdef XBRZ_PPL 00073 if (changedLines) // perf: in worst case similar to full input scaling 00074 { 00075 concurrency::task_group tg; // perf: task_group is slightly faster than pure parallel_for 00076 00077 int yLast = 0; 00078 Bitu y = 0, index = 0; 00079 while (y < sdl.draw.height) 00080 { 00081 if (!(index & 1)) 00082 y += changedLines[index]; 00083 else 00084 { 00085 const int sliceFirst = (int)y; 00086 const int sliceLast = (int)y + changedLines[index]; 00087 y += changedLines[index]; 00088 00089 int yFirst = max(yLast, sliceFirst - 2); // we need to update two adjacent lines as well since they are analyzed by xBRZ! 00090 yLast = min(srcHeight, sliceLast + 2); // (and make sure to not overlap with last slice!) 00091 for (int i = yFirst; i < yLast; i += sdl_xbrz.task_granularity) 00092 { 00093 tg.run([=] { 00094 const int iLast = min(i + sdl_xbrz.task_granularity, yLast); 00095 xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), i, iLast); 00096 }); 00097 } 00098 } 00099 index++; 00100 } 00101 tg.wait(); 00102 } 00103 else // process complete input image 00104 { 00105 concurrency::task_group tg; 00106 for (int i = 0; i < srcHeight; i += sdl_xbrz.task_granularity) 00107 { 00108 tg.run([=] { 00109 const int iLast = min(i + sdl_xbrz.task_granularity, srcHeight); 00110 xbrz::scale(scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), i, iLast); 00111 }); 00112 } 00113 tg.wait(); 00114 } 00115 #else 00116 /* non-PPL for non-Windows. 00117 * combine the code above, cleanly, if possible. */ 00118 if (changedLines) 00119 { 00120 int yLast = 0; 00121 Bitu y = 0, index = 0; 00122 while (y < sdl.draw.height) 00123 { 00124 if (!(index & 1)) 00125 y += changedLines[index]; 00126 else 00127 { 00128 const int sliceFirst = int(y); 00129 const int sliceLast = int(y + changedLines[index]); 00130 y += changedLines[index]; 00131 00132 int yFirst = max(yLast, sliceFirst - 2); // we need to update two adjacent lines as well since they are analyzed by xBRZ! 00133 yLast = min(srcHeight, sliceLast + 2); // (and make sure to not overlap with last slice!) 00134 xbrz::scale((size_t)scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), yFirst, yLast); 00135 } 00136 index++; 00137 } 00138 } 00139 else // process complete input image 00140 { 00141 xbrz::scale((size_t)scalingFactor, renderBuf, xbrzBuf, srcWidth, srcHeight, xbrz::ColorFormat::RGB, xbrz::ScalerCfg(), 0, srcHeight); 00142 } 00143 #endif /*XBRZ_PPL*/ 00144 } 00145 00146 #endif /*C_XBRZ*/ 00147 00148 #if C_XBRZ || C_SURFACE_POSTRENDER_ASPECT 00149 00150 void xBRZ_PostScale(const uint32_t* src, const int srcWidth, const int srcHeight, const int srcPitch, 00151 uint32_t* tgt, const int tgtWidth, const int tgtHeight, const int tgtPitch, 00152 const bool bilinear, const int task_granularity) 00153 { 00154 (void)task_granularity; 00155 00156 # if defined(XBRZ_PPL) 00157 if (bilinear) { 00158 concurrency::task_group tg; 00159 for (int i = 0; i < tgtHeight; i += task_granularity) 00160 tg.run([=] { 00161 const int iLast = min(i + task_granularity, tgtHeight); 00162 xbrz::bilinearScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, i, iLast, [](uint32_t pix) { return pix; }); 00163 }); 00164 tg.wait(); 00165 } 00166 else 00167 { 00168 concurrency::task_group tg; 00169 for (int i = 0; i < tgtHeight; i += task_granularity) 00170 tg.run([=] { 00171 const int iLast = min(i + task_granularity, tgtHeight); 00172 // perf: going over target is by factor 4 faster than going over source for similar image sizes 00173 xbrz::nearestNeighborScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, i, iLast, [](uint32_t pix) { return pix; }); 00174 }); 00175 tg.wait(); 00176 } 00177 #else 00178 if (bilinear) 00179 xbrz::bilinearScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, 0, tgtHeight, [](uint32_t pix) { return pix; }); 00180 else 00181 xbrz::nearestNeighborScale(&src[0], srcWidth, srcHeight, srcPitch, &tgt[0], tgtWidth, tgtHeight, tgtPitch, 0, tgtHeight, [](uint32_t pix) { return pix; }); 00182 #endif 00183 } 00184 00185 #endif /*C_XBRZ || C_SURFACE_POSTRENDER_ASPECT*/