当前位置: 首页 > 编程日记 > 正文

【原创】Linux环境下的图形系统和AMD R600显卡编程(11)——R600指令集

1 低级着色语言tgsi

OpenGL程序使用GLSL语言对可编程图形处理器进行编程,GLSL语言(以下高级着色语言就是指GLSL)是语法类似C的高级语言,在GLSL规范中,GLSL语言被先翻译成教低级的类汇编语言,然后被翻译成硬件特定的指令集。OpenGL体系管理委员会于2002年6月和2002年9月分别通过了两个官方扩展:ARB_VERTEX_PROGRAM与ARB_FRAGMENT_PROGRAM来统一对低级着色语言的支持,GLSL语言被编译成针对这两个扩展的低级着色语言(因此这两个扩展可以看成是GLSL运行的虚拟机),显卡厂商的驱动将低级着色语言翻译成GPU指令。这两个扩展的1.0版本分别是arbvpl0和arbfpl0,这两个扩展的2.0版本分别是arbvp20和arbfp2。

图1

目前,在Mesa上,GLSL首先被编译器翻译成tgsi中间语言,然后显卡特定的驱动将这些tgsi语言的代码编译成GPU指令,这个过程如图1示(不考虑geometry shader和tesselation shader)。这里有tgsi的详细描述。这篇硕士论文“高级着色语言及其优化编译”对GLSL和低级着色语言有比较详细的论述。

2 R600指令

在CPU上运行的程序,所有的访存指令和运算指令按照代码的堆叠顺序执行(不考虑指令集并行),如果有跳转指令则跳转到相应位置。

GPU主要用于运算,早期的GPU没有包含复杂的控制程序,R600 Shader程序和CPU程序比较显得比较简陋,必须有专门的代码指示程序的执行顺序,并且指示程序运行顺序的指令(Control Flow 指令,后面称为CF 指令)、运算指令(后面称ALU指令)和访存指令(在R600 GPU 中称为Fetch 指令)必须按照类别存放,同一种类型的指令放在一起,不同类型的指令按照某种顺序存放,同一类型的指令(不包括CF指令)构成一个Clause。图2显示了R600 GPU Shader程序在显存中存放的形式。

图2

R600的指令包含Control Flow(后面简称CF)指令,ALU(运算)指令,Vertex Fecth (取顶点)指令和Texture Fetch(取纹理)指令。指令的格式称为Microde Format。

每一个Shader程序(Pixel Shader或者Vertex Shader)包含两部分,一部分是CF指令,另一部分是Clause。 这些Clause由CF 指令初始化(或者不恰当的理解成Clause 由CF指令调用)。R600的每一条指令的格式(为了保持和手册上术语的一致,后面将使用Microcode Format这个词)都包含了2 个或者4个DWORD(CF 和ALU为2个DWORD,Vertex Fetch 和Texture Fetch 为4个DWORD,后面在说地址的时候都是以DWORD为单位的),这些Microcode Format可以在“R600 Family Instruction Set Architecture”手册上查阅到。

下面将使用两个实例来说明R600的指令集。和下面这两个实例等价的GLSL程序大概是这个样子的:

// vertex shader

attribute vec4 a_position;

attribute vec3 a_texture;

varying vec2 v_texCoord;

void main()

{

gl_Position = a_position;

v_texCoord = a_texture;

}

// pixel shader

uniform sample2D sampler;

varying vec2 v_texCoord;

void main ()

{

gl_FragColor = texture2D(sampler, v_texCoord);

}

3 Vertex Shader示例

下面使用一个具体的实例来说明,下面的程序来自我们的R600 EXA驱动的Copy过程的Vertex Shader(请参考后续章节),按照图2的要求,这段程序被分成了两部分,第一部分是CF指令,共四条指令,指令0~指令3(指令3为空指令,用于对齐),第二部分为取顶点指令,共两条指令,指令4~ 指令5,分别用于取顶点位置坐标和纹理坐标。

int R600_copy_vs(RADEONChipFamily ChipSet, uint32_t* shader)
{
  int i = 0;

/* 0   指令0 */
  shader[i++] = CF_DWORD0(ADDR(4));
  shader[i++] = CF_DWORD1(POP_COUNT(0), CF_CONST(0),
                COND(SQ_CF_COND_ACTIVE), I_COUNT(2), CALL_COUNT(0),
                END_OF_PROGRAM(0), VALID_PIXEL_MODE(0), CF_INST(SQ_CF_INST_VTX),
                WHOLE_QUAD_MODE(0), BARRIER(1));
  /* 1  指令1 */
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD0(ARRAY_BASE(CF_POS0), TYPE(SQ_EXPORT_POS), RW_GPR(1),
                RW_REL(ABSOLUTE), INDEX_GPR(0), ELEM_SIZE(0));
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD1_SWIZ(SRC_SEL_X(SQ_SEL_X), SRC_SEL_Y(SQ_SEL_Y), SRC_SEL_Z(SQ_SEL_Z),

SRC_SEL_W(SQ_SEL_W), R6xx_ELEM_LOOP(0), BURST_COUNT(0), END_OF_PROGRAM(0),

VALID_PIXEL_MODE(0), CF_INST(SQ_CF_INST_EXPORT_DONE), WHOLE_QUAD_MODE(0),
                BARRIER(1));
  /* 2  指令2 */
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD0(ARRAY_BASE(0), TYPE(SQ_EXPORT_PARAM), RW_GPR(0),
                RW_REL(ABSOLUTE), INDEX_GPR(0), ELEM_SIZE(0));
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD1_SWIZ(SRC_SEL_X(SQ_SEL_X), SRC_SEL_Y(SQ_SEL_Y),
                SRC_SEL_Z(SQ_SEL_Z), SRC_SEL_W(SQ_SEL_W), R6xx_ELEM_LOOP(0),
                BURST_COUNT(0), END_OF_PROGRAM(1), VALID_PIXEL_MODE(0),
                CF_INST(SQ_CF_INST_EXPORT_DONE), WHOLE_QUAD_MODE(0), BARRIER(0));
  /* 3  指令3*/
  shader[i++] = 0x00000000;
  shader[i++] = 0x00000000;
  /* 4/5 指令4 */
  shader[i++] = VTX_DWORD0(VTX_INST(SQ_VTX_INST_FETCH), FETCH_TYPE(SQ_VTX_FETCH_VERTEX_DATA),
                FETCH_WHOLE_QUAD(0), BUFFER_ID(0), SRC_GPR(0), SRC_REL(ABSOLUTE),
                SRC_SEL_X(SQ_SEL_X), MEGA_FETCH_COUNT(16));
  shader[i++] = VTX_DWORD1_GPR(DST_GPR(1), DST_REL(0), DST_SEL_X(SQ_SEL_X), DST_SEL_Y(SQ_SEL_Y),
                DST_SEL_Z(SQ_SEL_0), DST_SEL_W(SQ_SEL_1), USE_CONST_FIELDS(0),
                DATA_FORMAT(FMT_32_32_FLOAT), NUM_FORMAT_ALL(SQ_NUM_FORMAT_SCALED),
                FORMAT_COMP_ALL(SQ_FORMAT_COMP_SIGNED), SRF_MODE_ALL(SRF_MODE_ZERO_CLAMP_MINUS_ONE));

shader[i++] = VTX_DWORD2(OFFSET(0),
  #if X_BYTE_ORDER == X_BIG_ENDIAN
                ENDIAN_SWAP(SQ_ENDIAN_8IN32),
  #else
                ENDIAN_SWAP(SQ_ENDIAN_NONE),
  #endif
                CONST_BUF_NO_STRIDE(0), MEGA_FETCH(1));
  shader[i++] = VTX_DWORD_PAD;
  /* 6/7 指令5 */
  shader[i++] = VTX_DWORD0(VTX_INST(SQ_VTX_INST_FETCH), FETCH_TYPE(SQ_VTX_FETCH_VERTEX_DATA),

FETCH_WHOLE_QUAD(0), BUFFER_ID(0), SRC_GPR(0), SRC_REL(ABSOLUTE),
                SRC_SEL_X(SQ_SEL_X), MEGA_FETCH_COUNT(8));
  shader[i++] = VTX_DWORD1_GPR(DST_GPR(0), DST_REL(0), DST_SEL_X(SQ_SEL_X), DST_SEL_Y(SQ_SEL_Y),
                DST_SEL_Z(SQ_SEL_0), DST_SEL_W(SQ_SEL_1), USE_CONST_FIELDS(0),

DATA_FORMAT(FMT_32_32_FLOAT), NUM_FORMAT_ALL(SQ_NUM_FORMAT_SCALED),
                FORMAT_COMP_ALL(SQ_FORMAT_COMP_SIGNED),
                SRF_MODE_ALL(SRF_MODE_ZERO_CLAMP_MINUS_ONE));
  shader[i++] = VTX_DWORD2(OFFSET(8),
  #if X_BYTE_ORDER == X_BIG_ENDIAN
                ENDIAN_SWAP(SQ_ENDIAN_8IN32),
  #else
                ENDIAN_SWAP(SQ_ENDIAN_NONE),
  #endif
                CONST_BUF_NO_STRIDE(0), MEGA_FETCH(0));
  shader[i++] = VTX_DWORD_PAD;

return i;
}

上面程序的运行过程如

结合下面这几张图详细描述程序运行的过程。

图3

图4

图5

图3示,初始状态,图中有两个线程,此刻两个线程正在要两个顶点数据进行处理。

  • CF指令0, 指令0的ADDR位指示程序从地址4处的指令(指令4)开始运行,I_COUNT位指示共执行2条指令(指令4和指令5),执行完后回到指令0,指令0的END_OF_PROGRAM位表明程序还没有结束,继续执行CF指令1。
  • Vertex Fetch Clause,CF的指令0指明程序会从第指令4处开始执行,指令4和指令5构成一个Vertex Fetch Clause,两条指令一起完成取顶点数据,这里是要进行Copy操作,顶点数据包括顶点的位置坐标和纹理坐标。由于是2D操作,因此这里的坐标的有效分量只有两个。 指令4的VTX_INST位表明改指令是一条取数据的指令,从BUFFER_ID为0 的内存处取顶点(FETCH_TYPE)数据,SRC_GPR为索引号所在的源寄存器位置,一次取的数据量为16字节(一个四元向量的大小),取出来的数据被放置在编号为1的寄存器中(DST_GPR),DST_SEL_X(SQ_SEL_X)表明取出来的向量的X分量放置到目的寄存器第一个DWORD位置处,Y分量放置到第二个DWORD(DST_SEL_Y(SQ_SEL_Y)),目的寄存器的第三个DWORD 处被置为0,第四个DWORD 处被置为1(可以使用0,1或者0.5)。指令5和指令4类似,由于所有顶点属性数据已经取完,因此原来存在于GPR0 的地址不再需要,可以覆盖掉。图4。
  • CF指令1和指令2,这是两条输出指令,指令所做的工作如图5示,指令1用于输出顶点的位置坐标(TYPE(SQ_EXPORT_POS)),这条指令从GPR1(RW_GPR(1))中读取数据,将数据输出到Position Buffer 0 中(ARRAY_BASE(CF_POS0))。输出的时候还有一个Swizzle操作,这条指令的Swizzle操作没有变换向量各个分量。指令1的END_OF_PROGRAM标志表明程序还没有结束,因此继续执行指令2,指令2的END_OF_PROGRAM位表明程序至此结束(后面如果还写有指令将不会被执行)。

4 Pixel Shader示例

/* copy ps --------------------------------------- */
int R600_copy_ps(RADEONChipFamily ChipSet, uint32_t* shader)
{
  int i=0;

/* CF INST 指令 0 */
  shader[i++] = CF_DWORD0(ADDR(2));
  shader[i++] = CF_DWORD1(POP_COUNT(0), CF_CONST(0), COND(SQ_CF_COND_ACTIVE), I_COUNT(1),
              CALL_COUNT(0), END_OF_PROGRAM(0), VALID_PIXEL_MODE(0), CF_INST(SQ_CF_INST_TEX),
              WHOLE_QUAD_MODE(0), BARRIER(1));
  /* CF INST 指令 1 */
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD0(ARRAY_BASE(CF_PIXEL_MRT0), TYPE(SQ_EXPORT_PIXEL), RW_GPR(0),
              RW_REL(ABSOLUTE), INDEX_GPR(0), ELEM_SIZE(1));
  shader[i++] = CF_ALLOC_IMP_EXP_DWORD1_SWIZ(SRC_SEL_X(SQ_SEL_X), SRC_SEL_Y(SQ_SEL_Y),

SRC_SEL_Z(SQ_SEL_Z), SRC_SEL_W(SQ_SEL_W), R6xx_ELEM_LOOP(0), BURST_COUNT(1),
              END_OF_PROGRAM(1), VALID_PIXEL_MODE(0), CF_INST(SQ_CF_INST_EXPORT_DONE),
              WHOLE_QUAD_MODE(0), BARRIER(1));
  /* TEX INST 指令 2 */
  shader[i++] = TEX_DWORD0(TEX_INST(SQ_TEX_INST_SAMPLE), BC_FRAC_MODE(0), FETCH_WHOLE_QUAD(0),
              RESOURCE_ID(0), SRC_GPR(0), SRC_REL(ABSOLUTE), R7xx_ALT_CONST(0));
  shader[i++] = TEX_DWORD1(DST_GPR(0), DST_REL(ABSOLUTE), DST_SEL_X(SQ_SEL_X), /* R */

DST_SEL_Y(SQ_SEL_Y), /* G */
              DST_SEL_Z(SQ_SEL_Z), /* B */
              DST_SEL_W(SQ_SEL_W), /* A */
              LOD_BIAS(0),
              COORD_TYPE_X(TEX_UNNORMALIZED), COORD_TYPE_Y(TEX_UNNORMALIZED),
              COORD_TYPE_Z(TEX_UNNORMALIZED), COORD_TYPE_W(TEX_UNNORMALIZED));
  shader[i++] = TEX_DWORD2(OFFSET_X(0), OFFSET_Y(0), OFFSET_Z(0), SAMPLER_ID(0), SRC_SEL_X(SQ_SEL_X),
              SRC_SEL_Y(SQ_SEL_Y), SRC_SEL_Z(SQ_SEL_0), SRC_SEL_W(SQ_SEL_1));
  shader[i++] = TEX_DWORD_PAD;

return i;
}

这里总共三条指令,其中CF指令0和CF指令1是两条CF指令,TEX指令2是一条取纹理的指令。

指令0表明程序将从addr为2的指令2处开始执行,指令2是一条texture fetch 指令,这条指令根据GPR0中给出的纹理坐标(SRC_GPR(0),根据前面semantic的配置,被插值的纹理坐标存放在GPR0中)从id号为0的纹理资源中取出纹理值,放入到GPR0中(DST_GPR(0x0))。

取纹理操作完成后,执行指令1,指令1是一条输出指令,将取到的纹理直接放到Render target 0(ARRAY_BASE(CF_PIXEL_MRT0))上去。

R600显卡的指令远不止以上这些,读者在理解上面的内容之后,阅读R600指令集手册将不会有太大困难,感兴趣的可以深入进去了解更多的指令。

转载于:https://www.cnblogs.com/shoemaker/p/linux_graphics11.html

相关文章:

VBScript中InStr函数的用法

InStr([start, ]str1, str2[, compare]) [用途]:返回str2在str1中的位置。匹配成功时,返回值最小值为1,未匹配到时返回0。 [参数说明]: start:在str1中开始匹配的位置,1表示从头开始,不能为0或更小值。 可选…

洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)

题面 传送门 题解 题目转化一下就是所有点都在直线\(AxBy-C0\)的同一侧,也就可以看做所有点代入\(AxBy-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看看每条直线的最大最小值符号是否相同就好了 以最大值为例&am…

skiplist跳表的 实现

文章目录前言跳表结构时间复杂度空间复杂度高效的动态插入和删除跳表索引的动态更新总结详细实现前言 rocksdb 的memtable中默认使用跳表数据结构对有序数据进行的管理,为什么呢? 同时redis 也用跳表作为管理自己有序集合的数据结构,为什么…

php的反射作用是什么意思,php反射的作用是什么

反射是在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取的信息以及动态调用对象的方法的功能称为反射API。反射是操纵面向对象范型中元模型的API,其功能十分强大&#…

《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集

《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集 原文:《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集用Excel2013连接和浏览OLAP多维数据集 posted on 2014-12-02 08:58 NET未来之路 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/lonelyxmas/p/413…

mac 拷贝文件时报错 8060 解决方案

解决如下: 即某文件夹下出现多重子目录,级数很多,删除多余的子文件夹即可。 至于如何产生的,有人说是xcode升级导致,不过没有见证 。我的不属于这类情况的。 (参见:http://macosx.com/forums/ma…

C#连接数据库

VScode 配置C#环境 https://blog.csdn.net/qq_40346899/article/details/80955788VScode 配置C#开发环境 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;using System.Data; using System.Data.SqlCli…

C++ 中emplace_back和push_back差异

前言 最近看rocskdb源码,发现了大量的设计模式和C高级特性,特此补充一下,巩固基础。 问题描述 其中关于动态数组的元素添加,代码中基本将push_back抛弃掉了,全部替换为emplace_back进行元素的添加。 看了一下官网描…

[51单片机学习笔记ONE]-----LED灯的多种使用方法

一.交替闪烁8个LED灯,时间间隔为1s 1 /******************************************************2 实验名称: 交替闪烁8个LED灯,时间间隔1s3 实验时间: 2014年12月2日4 ******************************************************/…

php 伪协议 lfi,php://伪协议(I/O)总能给你惊喜——Bugku CTF-welcome to bugkuctf

今天一大早BugkuCTF 的welcome to bugkuctf 就给了我一发暴击:完全不会啊。。。光看源码就发现不知道怎么处理了,于是转向writeup求助。结果发现这是一道非常有营养的题目,赶紧记录一下。题目链接:http://123.206.87.240:8006/tes…

Pascal's Triangle

帕斯卡三角形&#xff0c;主要考察vector的用法。 vector<vector<int> > generate(int numRows){vector<vector<int> > result;vector<int> tmp;result.clear();tmp.clear();int i,j;if(numRows 0)return result;else if(numRows 1){tmp.push_…

SpringBoot请求转发与重定向

但是可能由于B网址相对于A网址过于复杂,这样搜索引擎就会觉得网址A对用户更加友好,因而在重定向之后任然显示旧的网址A,但是显示网址B的内容。在平常使用手机的过程当中,有时候会发现网页上会有浮动的窗口,或者访问的页面不是正常的页面,这就可能是运营商通过某种方式篡改了用户正常访问的页面。重定向,是指在Nginx中,重定向是指通过修改URL地址,将客户端的请求重定向到另一个URL地址的过程,Nginx中实现重定向的方式有多种,比如使用rewrite模块、return指令等。使用场景:在返回视图的前面加上。

SSO 单点登录和 OAuth2.0 有何区别?

此方法的缺点是它依赖于浏览器和会话状态,对于分布式或者微服务系统而言,可能需要在服务端做会话共享,但是服务端会话共享效率比较低,这不是一个好的方案。在单点登录的上下文中,OAuth 可以用作一个中介,用户在一个“授权服务器”上登录,并获得一个访问令牌,该令牌可以用于访问其他“资源服务器”上的资源。首先,SSO 主要关注用户在多个应用程序和服务之间的无缝切换和保持登录状态的问题。这种方法通过将登录认证和业务系统分离,使用独立的登录中心,实现了在登录中心登录后,所有相关的业务系统都能免登录访问资源。

【转】linux服务器性能查看

转载自https://blog.csdn.net/achenyuan/article/details/78974729 1.1 cpu性能查看 1、查看物理cpu个数&#xff1a; cat /proc/cpuinfo |grep "physical id"|sort|uniq|wc -l 2、查看每个物理cpu中的core个数&#xff1a; cat /proc/cpuinfo |grep "cpu cores…

Rocksdb 内存“不释放”问题 分析

文章目录问题场景描述问题复现编写随机写 测试工具使用工具抓取内存分配过程源码分析memtable逻辑table_cache逻辑总结整体的IO场景到底层的源码分析过程如上导图&#xff0c;接下来将详细阐述具体的过程。问题场景描述 我们的rocksdb作为单机存储引擎&#xff0c;跑在用分布式…

GitHub上整理的一些工具【转载】

技术站点Hacker News&#xff1a;非常棒的针对编程的链接聚合网站Programming reddit&#xff1a;同上MSDN&#xff1a;微软相关的官方技术集中地&#xff0c;主要是文档类infoq&#xff1a;企业级应用&#xff0c;关注软件开发领域OSChina&#xff1a;开源技术社区&#xff0c…

show在php,show.php

我的留言板function dodel(id){if(confirm("确定要删除么&#xff1f;")){window.location del.php?idid;}}我的留言板添加留言查看留言查看留言留言标题留言人留言内容IP地址留言时间操作// 获取留言信息&#xff0c;解析后输出到表格中// 1.从留言liuyan.txt中获取…

#天天复制,今天写一个# 把文字转为图片

/*** 把文字转为图片* * param text* 要写的内容* throws IOException*/public static void textToImg(String text) throws IOException {int len text.length();int fontSize 1000;int width len * fontSize;Font font new Font("楷体", Font2D.NAT…

spark(3) - scala独立编程

>>非集成&#xff1a; 环境需要 * spark 2.4.0 * scala 2.11.12 * sbt &#xff08;打包&#xff09; 开发过程 1、shell命令下创建项目目录结构 *****/ project / src / main / scala -> . / ClassName.scala &#xff08; touch gedit 命令&#xff09; …

C++ STL: 基本六大部件概览 及 各个容器使用方式和底层实现概览

文章目录STL六大部件容器的使用Arrayvectorlistdequemutisetmultimapunordered_multiset/set使用一个东西&#xff0c;却不明白它的道理&#xff0c;不高明。STL六大部件 容器 Containers 用来存放数据分配器 Allocators 为容器内的数据分配存储空间算法 Algorithms 计算数据迭…

Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析

文章转载至CSDN社区罗升阳的安卓之旅&#xff0c;原文地址&#xff1a;http://blog.csdn.net/luoshengyang/article/details/8570428 通过前面几篇文章的学习&#xff0c;我们知道了在 Android系统中&#xff0c;无论是普通的Activity窗口&#xff0c;还是特殊的输入法窗口和壁…

oracle非归档模式下如何备份,Oracle之RMAN数据库在非归档模式下的备份和恢复

1.数据库在非归档模式下的备份 SQLgt; archive log list;数据库日志模式 非存档模式自动存档 禁用存档终点 USE_DB_RECOVERY_FIL1.数据库在非归档模式下的备份SQL> archive log list;数据库日志模式 非存档模式自动存档 禁用存档终点 USE_DB_RECOVERY_FILE_DEST最早的联机日…

C# 视频多人脸识别的实现

上一篇内容的调整&#xff0c;提交到git了&#xff0c;https://github.com/catzhou2002/ArcFaceDemo基本思路如下&#xff1a;一、识别线程1.获取当前图片2.识别当前图片的人脸位置&#xff0c;并将结果存入列表3.分别获取人脸的特征值并比对&#xff0c;并将结果存入列表4.如果…

C++ STL: 分配器allocators 源码分析

STL 基本的六大组件作用以及功能如下&#xff1a; 可以看到allocator是数据存储组件container的幕后支持者&#xff0c;负责为其数据存储分配对应的存储空间。 operator::new 在详细介绍alloctor之前&#xff0c;先描述一下new运算符&#xff0c;我们使用C new一个对象的时候…

android xUtils的使用

gethub地址&#xff1a;https://github.com/wyouflf/xUtils/ xUtils简介 xUtils 包含了很多实用的android工具。xUtils 支持大文件上传&#xff0c;更全面的http请求协议支持(10种谓词)&#xff0c;拥有更加灵活的ORM&#xff0c;更多的事件注解支持且不受混淆影响...xUitls 最…

oracle 条件反转,Oracle反转倒置函数

Oracle提供了一个反转倒置函数reverse&#xff0c;但此函数不能分组倒置&#xff0c;本文提供了一个即可分组倒置的函数&#xff0c;如下所示&#xff1a;CREATE OR REPLACE FUNCTION REVERSE_F(p_str VARCHAR2, p_delimiter VARCHAR2:)RETURN VARCHAR2 ISv_return VARCHAR2(40…

android读取大图片并缓存

最近开发电视版的云存储应用&#xff0c;要求”我的相册“模块有全屏预览图片的功能&#xff0c;全屏分辨率是1920*1080超清。UI组件方面采用GalleryImageSwitcher组合&#xff0c;这里略过&#xff0c;详情参见google Android API。相册图片预取缓存策略是内存缓存&#xff08…

[ZJOI2018]历史

Description: 给定一棵树,定义每个点的操作为把这个点到1号点的路径覆盖上颜色i,每次该点到1号点经过的不同颜色段数会加到答案中,要使所有点按某一顺序操作完后答案最大 给定每个点要执行的操作次数,并给出m次修改,问每次修改后的最大答案 Hint: \(n,m \le 4*10^5\) Solution:…

C++ STL: lower_bound 和 upper_bound

接口声明 以下有两个不同的版本 lower_bound template <class ForwardIterator, class T>ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val);template <class ForwardIterator, class T, class Compare>ForwardItera…

1199: 房间安排

1199: 房间安排 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1 Solved: 1[Submit][Status][Web Board]Description 2010年上海世界博览会(Expo2010),是第41届世界博览会。于2010年5月1日至10月31日期间&#xff0c;在中国上海市举行。本次世博会也是由中国举办的首届世界…